[git] GnuPG - branch, neal/next, updated. gnupg-2.1.9-89-g692fe5f

by Neal H. Walfield cvs at cvs.gnupg.org
Thu Oct 29 10:20:50 CET 2015


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, neal/next has been updated
  discards  8b34fae89eab607c35f9f414549d886d3e1a0ed3 (commit)
       via  692fe5f7ac301d828085f7685e451fec3f6d06bb (commit)
       via  641df615da4937b0073c420a0503c5810c237972 (commit)
       via  d68bdc553a206e54234d5d53ad35c4ba34133118 (commit)
       via  ef052591ba51ee16bafc3c5b79d837ed8f01b520 (commit)
       via  89eee5f6b7ca3da7ebdcc3e5d069701d0834b39e (commit)
       via  99c84b49b787dab8da26cf61eed24dd4a2b77fd9 (commit)
       via  421827424fe87855307fe3e803b42ffa02738600 (commit)
       via  351f4213e192aa11500c0c590d11183edbe326c5 (commit)
       via  d25e29ad9374da1c11ccfc38f392dbab2d707042 (commit)
       via  8b6c83dcb086ef09b2676e4d5b0111c88b7b8bf8 (commit)
       via  e095a3fcf2ccc6cc4e258111dc395558069a1164 (commit)
       via  fa15a71daff8414bf4112bc2826dc495ff2fb01f (commit)
       via  1f872cb4ad2d3dcc3598fed689504c9731600caa (commit)
       via  02dc518787c5d8525c18986947a59c8ef1bd41da (commit)
       via  949a5cfdabcafab93c1ac092c0459b59318805b9 (commit)
       via  e026efb4363bc6e3c41ed533daf06f103ebd2e32 (commit)
       via  a6c2c098435a703ca02abf651ff4fa45e5a4db9a (commit)
       via  91015d021b3dcbe21ad0e580a4f34c523abf9e72 (commit)
       via  0d37a40fc34519e93af3ceffff2cd726d29576d3 (commit)
       via  68100b4a0b6118cfd2813fa73ace0df441079379 (commit)
       via  4524a2a3714f263d56bb7db349c169b456994fd9 (commit)
       via  7735bbe539af35ce16e270946d5ae798c5989d6e (commit)
       via  c18fb0d99b633bb267dead6e7c46229f4b780bc3 (commit)
       via  5b0ed7674dc718ee98e0c80aa93ce014f2b51411 (commit)
       via  5e7ac031f513ad3b60e4f092fa72b3bec0676515 (commit)
       via  0e3c9f184a5fb3e41277700d690febc2eee9600a (commit)
       via  927f34603d942868af6a7bd0f347681bbad76a94 (commit)
       via  816505958ac4308ee0dfe787d1b706982428b6cc (commit)
       via  7f65e84ac035e8f7a25639a6b09eb6000115e337 (commit)
       via  297cf8660ce346638e42934d84d746768f8bb10a (commit)
       via  cd879d4bd69a578be5a1ff96497f8c1181885563 (commit)
       via  3c4c89cc35280164b509977c5288b0a06d6f530e (commit)
       via  8b06d7f41aec6cb993445935dba7c60e033d026a (commit)
       via  e03a4a94bb67d4a6c958b37671f83456e203f325 (commit)
       via  41bb01ae792af78edd28bf1b735cacc0b3ac428a (commit)
       via  1e34007c972c1d7730cfcacd88f6bbebba7dec1d (commit)
       via  b6af3377e14fad35b9c6041b11888cabce6e8a56 (commit)
       via  6fafda979df8e7e117f8e6929bcce89513a6e746 (commit)
       via  03e230f0ea62fa7ec363e727ea1cf1344643464f (commit)
       via  9ffcb77e2565651afdeda523374bcbb24b5bd735 (commit)
       via  afbe87fa2d259b665b2d67a038a8535cfcfee094 (commit)
       via  8bccbf477878fd99baa96e11db9db99aaf1e8d91 (commit)
       via  ffe60eb3d2b8f7d6c506804ce4645d695c91f237 (commit)
       via  9afeb4cca10c3632495fe71b23df99a4878bd3a5 (commit)
       via  8c3b7915d675ca5346c17244654d5c6ab583ac44 (commit)
       via  cbaca254ac818c49c18d4480d3c7bd246cc57ae8 (commit)
       via  df57390d68482c5b3fa5ff3a42a29ae1b6cbb23c (commit)
       via  d05ff81732e20e6f9d6d7a6281a96a312b001abb (commit)
       via  243f90afba87e99ca42e2451ac5cc59d00a044ac (commit)
       via  a79045e38d239a7f6e787cf7c1132772c737cc0e (commit)
       via  85bd7d9491f8cc13c2b03f19b4f70ea13b45c704 (commit)
       via  485e0a221deb5c68f29b6a7a110b349dbe41c027 (commit)
       via  5055b617a94587580bc16a56bb82333077b05693 (commit)
       via  42571a38344e39f747315f754700a8181b8744fe (commit)
       via  58ebe50bdf4837e9ab2d3f8c6e5fcf28c66f26e9 (commit)
       via  c83b627174f46e841f1ccc018322fe499969c267 (commit)
       via  734c61dc9d4915605816803182c9adcc1594e008 (commit)
       via  26d457c218c2e93b2e2cf316f0c1074c70894d0f (commit)
       via  bc9ff6c85e2d89be4ee873b8a72a214759a66157 (commit)
       via  251c070f91e2c65baa3f1195f14a176440a8aafa (commit)
       via  d3eca517745a862432fcfeaa729e5333b15ffa6a (commit)
       via  445f94bc81b20959a667a4ad80ea6c73059540bf (commit)
       via  4957e3236796979b58f35628351505ea5f4e936a (commit)
       via  eb8a0b051faa03584b3820200e10301936e82f51 (commit)
       via  c3bb9fccb7963a0918b9ec6a4f10d568fac7c125 (commit)
       via  d1a0b520b15bb941cdbf66c2e832c617af778ac8 (commit)
       via  4e42ad300b3de9fab25095a9e82431b1ea2740e7 (commit)
       via  c37621166e9cc2a818de73bc99287a393dbb5744 (commit)
       via  a608ee750dd83bf77a5fb4f0ab5bcf812436ba4d (commit)
       via  0433e667029508d6933e8798d3d95bcdde70a7aa (commit)
       via  547a1b3fb881bb8581d03dbf4eacf49163eaa4b5 (commit)
       via  b98939812abf6c643c752ce7c325f98039a1a9e2 (commit)
       via  76afaed65e3b0ddfa4923cb577ada43217dd4b18 (commit)
       via  6983fd131f648ba4acd57b266de9868911874d14 (commit)
       via  8c609eaf35b547f02979ef0b206520dd0853b294 (commit)
       via  253afa244487dd8129816615ac2865c9fe812aaf (commit)
       via  e56a116f9a1171ccf8b3293887a217953a46fc20 (commit)
       via  55d88454652543c98d74376977d855e394df6c92 (commit)
       via  c2c400714854d5a127a6966200d345d0d6cfc7d4 (commit)
       via  558bcd43ae0a841cf1e58e06f5d72a19d5bc70cd (commit)
       via  e64c805b0c270d859ddf2c35d573110cf25e8d48 (commit)
       via  5aa1b392b1bf6fcf4cd380862c5affac39a4f34d (commit)
       via  128a456e775edf393d47e40bb9ae8b62434e2978 (commit)
       via  f77913e0ff7be4cd9c6337a70ac715e6f4a43572 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (8b34fae89eab607c35f9f414549d886d3e1a0ed3)
            \
             N -- N -- N (692fe5f7ac301d828085f7685e451fec3f6d06bb)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 692fe5f7ac301d828085f7685e451fec3f6d06bb
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Oct 29 10:18:13 2015 +0100

    New key db.

diff --git a/g10/Makefile.am b/g10/Makefile.am
index 2fe5c9a..766e4b7 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -29,7 +29,7 @@ include $(top_srcdir)/am/cmacros.am
 AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \
             $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
 
-needed_libs = ../kbx/libkeybox.a $(libcommon)
+needed_libs = ../kbx/libkeybox.a $(libcommon) $(SQLITE3_LIBS)
 
 bin_PROGRAMS = gpg2
 if !HAVE_W32CE_SYSTEM
@@ -57,7 +57,7 @@ trust_source = trustdb.c trustdb.h tdbdump.c tdbio.c tdbio.h
 endif
 
 if USE_TOFU
-tofu_source = tofu.h tofu.c sqlite.c sqlite.h
+tofu_source = tofu.h tofu.c
 else
 tofu_source =
 endif
@@ -101,7 +101,9 @@ common_source =  \
 	      sig-check.c	\
 	      keylist.c 	\
 	      pkglue.c pkglue.h \
-	      ecdh.c
+	      ecdh.c            \
+	      kdb.c kdb.h       \
+	      sqlite.c sqlite.h
 
 gpg2_SOURCES  = gpg.c		\
 	      server.c          \
@@ -147,7 +149,7 @@ gpgv2_SOURCES = gpgv.c           \
 
 LDADD =  $(needed_libs) ../common/libgpgrl.a \
          $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
-gpg2_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+gpg2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
              $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
 	     $(LIBICONV) $(resource_objs) $(extra_sys_libs)
 gpg2_LDFLAGS = $(extra_bin_ldflags)
diff --git a/g10/kdb.c b/g10/kdb.c
new file mode 100644
index 0000000..a60c884
--- /dev/null
+++ b/g10/kdb.c
@@ -0,0 +1,938 @@
+#include <config.h>
+#include <assert.h>
+#include <sqlite3.h>
+
+#include "gpg.h"
+#include "util.h"
+#include "logging.h"
+#include "i18n.h"
+#include "mbox-util.h"
+#include "sqlite.h"
+
+#include "kdb.h"
+
+struct kdb_resource
+{
+  struct kdb_resource *next;
+  int read_only;
+  sqlite3 *db;
+  char fname[1];
+};
+typedef struct kdb_resource *KDB_RESOURCE;
+typedef struct kdb_resource const * CONST_KDB_RESOURCE;
+
+/* All registered resources.  */
+static KDB_RESOURCE kdb_resources;
+
+struct keydb_handle {
+  CONST_KDB_RESOURCE resource;
+  /* Current key.  */
+  long long int key;
+  int eof;
+  struct {
+    long long int key;
+    int pk_no;
+    int uid_no;
+  } found, saved_found;
+};
+
+/* RESOURCE is a value returned by a previous call to
+   kdb_register_file in *RESOURCEP.  */
+KDB_HANDLE
+kdb_new (void *resource)
+{
+  KDB_RESOURCE r;
+  KDB_HANDLE hd;
+
+  /* Assert that the resource was indeed previously registered.  */
+  for (r = kdb_resources; r; r = r->next)
+    if (r == resource)
+      break;
+  assert (r);
+
+  hd = xmalloc_clear (sizeof (*hd));
+  hd->resource = resource;
+  hd->key = -1;
+  return hd;
+}
+
+
+/* Collect a series of integers from a query.  Aborts if the argument
+   is not a valid integer (or real of the form X.0).  COOKIE points to
+   an array of unsigned long ints, which has enough space for ARGC
+   values.  */
+static int
+get_unsigned_longs_cb (void *cookie, int argc, char **argv, char **azColName)
+{
+  unsigned long int *values = cookie;
+  int i;
+  char *tail = NULL;
+
+  (void) azColName;
+
+  for (i = 0; i < argc; i ++)
+    {
+      errno = 0;
+      values[i] = strtoul (argv[i], &tail, 0);
+      if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
+        /* Abort.  */
+        return 1;
+    }
+
+  return 0;
+}
+
+static int
+get_unsigned_longs_cb2 (void *cookie, int argc, char **argv, char **azColName,
+                        sqlite3_stmt *stmt)
+{
+  (void) stmt;
+  return get_unsigned_longs_cb (cookie, argc, argv, azColName);
+}
+
+/* We expect a single integer column whose name is "version".  COOKIE
+   must point to an int.  This function always aborts.  On error or a
+   if the version is bad, sets *VERSION to -1.  */
+static int
+version_check_cb (void *cookie, int argc, char **argv, char **azColName)
+{
+  int *version = cookie;
+
+  if (argc != 1 || strcmp (azColName[0], "version") != 0)
+    {
+      *version = -1;
+      return 1;
+    }
+
+  if (strcmp (argv[0], "1") == 0)
+    *version = 1;
+  else
+    {
+      log_error (_("unsupported TOFU DB version: %s\n"), argv[0]);
+      *version = -1;
+    }
+
+  /* Don't run again.  */
+  return 1;
+}
+
+/* Register a new file.  If the file has already been registered then
+   returns NULL otherwise returns */
+gpg_error_t
+kdb_register_file (const char *fname, int read_only, void **resourcep)
+{
+  KDB_RESOURCE resource;
+  int rc;
+  sqlite3 *db = NULL;
+  char *err;
+  unsigned long int count;
+  int need_init = 1;
+
+  for (resource = kdb_resources; resource; resource = resource->next)
+    if (same_file_p (resource->fname, fname))
+      {
+        if (resourcep)
+          *resourcep = resource;
+        if (read_only)
+          resource->read_only = 1;
+        return 0;
+      }
+
+  rc = sqlite3_open_v2 (fname, &db,
+                        read_only
+                        ? SQLITE_OPEN_READONLY
+                        : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE),
+                        NULL);
+  if (rc)
+    {
+      log_error ("Failed to open the key db '%s': %s\n",
+                 fname, sqlite3_errstr (rc));
+      return rc;
+    }
+
+  /* If the DB has no tables, then assume this is a new DB that needs
+     to be initialized.  */
+  rc = sqlite3_exec (db,
+		     "select count(*) from sqlite_master where type='table';",
+		     get_unsigned_longs_cb, &count, &err);
+  if (rc)
+    {
+      log_error (_("error querying kdb's available tables: %s\n"),
+		 err);
+      sqlite3_free (err);
+      goto out;
+    }
+  else if (count != 0)
+    /* Assume that the DB is already initialized.  Make sure the
+       version is okay.  */
+    {
+      int version = -1;
+      rc = sqlite3_exec (db, "select version from version;", version_check_cb,
+			 &version, &err);
+      if (rc == SQLITE_ABORT && version == 1)
+	/* Happy, happy, joy, joy.  */
+	{
+	  sqlite3_free (err);
+          rc = 0;
+          need_init = 0;
+	}
+      else if (rc == SQLITE_ABORT && version == -1)
+	/* Unsupported version.  */
+	{
+	  /* An error message was already displayed.  */
+	  sqlite3_free (err);
+          goto out;
+	}
+      else if (rc)
+	/* Some error.  */
+	{
+	  log_error (_("error determining kdb's version: %s\n"), err);
+	  sqlite3_free (err);
+          goto out;
+	}
+      else
+	/* Unexpected success.  This can only happen if there are no
+	   rows.  */
+	{
+	  log_error (_("error determining kdb's version: %s\n"),
+		     "select returned 0, but expected ABORT");
+          rc = 1;
+          goto out;
+	}
+    }
+
+  if (need_init)
+    {
+      /* Create the version table.  */
+      rc = sqlite3_exec (db,
+                         "create table version (version INTEGER);",
+                         NULL, NULL, &err);
+      if (rc)
+        {
+          log_error (_("error initializing kdb database (%s): %s\n"),
+                     "version", err);
+          sqlite3_free (err);
+          goto out;
+        }
+
+      /* Initialize the version table, which contains a single integer
+         value.  */
+      rc = sqlite3_exec (db,
+                         "insert into version values (1);",
+                         NULL, NULL, &err);
+      if (rc)
+        {
+          log_error (_("error initializing kdb database (%s): %s\n"),
+                     "version, init", err);
+          sqlite3_free (err);
+          goto out;
+        }
+
+      /* We have 3 tables:
+
+         primaries - the list of all primary keys and the key block.
+
+         keys - the list of all keys and subkeys.
+
+         user ids - the list of all user ids.  */
+
+      rc = sqlite3_exec
+        (db,
+         /* Enable foreign key constraints.  */
+         "pragma foreign_keys = on;\n"
+         "create table primaries\n"
+         " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+         "  fingerprint_rev TEXT COLLATE NOCASE, keyblock BLOB);\n"
+         "create index primaries_fingerprint on primaries\n"
+         " (fingerprint_rev COLLATE NOCASE);\n"
+         "\n"
+         "create table keys\n"
+         " (primary_key INTEGER, fingerprint_rev TEXT COLLATE NOCASE,\n"
+         "  pk_no INTEGER,\n"
+         "  unique (primary_key, pk_no),\n"
+         "  foreign key (primary_key) references primaries(oid));\n"
+         "create index keys_fingerprint_primary_key_pk_no on keys\n"
+         " (fingerprint_rev COLLATE NOCASE, primary_key, pk_no);\n"
+         "create index keys_primary_key_pk_no on keys (primary_key, pk_no);\n"
+         "\n"
+         /* XXX: Is COLLATE NOCASE reasonable?  */
+         "create table uids\n"
+         " (primary_key INTEGER, uid TEXT COLLATE NOCASE,\n"
+         "  email TEXT COLLATE NOCASE, uid_no INTEGER,\n"
+         "  unique (primary_key, uid_no),\n"
+         "  foreign key (primary_key) references primaries(oid));\n"
+         "create index uids_ordered on uids (primary_key, uid_no);\n"
+         /* In most cases, we search for a substring (like
+            '%foo at bar.com%'.  This can't exploit an index so the
+            following indices mostly represent overhead.  */
+#if 0
+         "create index uids_uid_ordered on uids\n"
+         " (uid COLLATE NOCASE, primary_key, uid_no);\n"
+         "create index uids_email_ordered on uids\n"
+         " (email COLLATE NOCASE, primary_key, uid_no);\n"
+#endif
+         ,
+         NULL, NULL, &err);
+      if (rc)
+        {
+          log_error (_("error initializing kdb database: %s\n"), err);
+          sqlite3_free (err);
+          goto out;
+        }
+    }
+
+  resource = xmalloc_clear (sizeof *resource + strlen (fname));
+  strcpy (resource->fname, fname);
+  resource->read_only = read_only;
+  resource->db = db;
+  resource->next = kdb_resources;
+  kdb_resources = resource;
+
+  if (resourcep)
+    *resourcep = resource;
+
+ out:
+  if (rc)
+    {
+      if (resourcep)
+        *resourcep = NULL;
+
+      sqlite3_close (db);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  return 0;
+}
+
+int
+kdb_is_writable (void *token)
+{
+  KDB_RESOURCE resource = token;
+  if (resource->read_only)
+    return 0;
+  return 1;
+}
+
+/* Release the handle.  */
+void
+kdb_release (KDB_HANDLE hd)
+{
+  KDB_RESOURCE r;
+
+  if (! hd)
+    return;
+
+  /* Check for double frees.  */
+  assert (hd->resource);
+  for (r = kdb_resources; r; r = r->next)
+    if (r == hd->resource)
+      break;
+  assert (r);
+
+  hd->resource = NULL;
+
+  xfree (hd);
+}
+
+void
+kdb_push_found_state (KDB_HANDLE hd)
+{
+  hd->saved_found = hd->found;
+  hd->found.key = -1;
+}
+
+void
+kdb_pop_found_state (KDB_HANDLE hd)
+{
+  hd->found = hd->saved_found;
+  hd->saved_found.key = -1;
+}
+
+const char *
+kdb_get_resource_name (KDB_HANDLE hd)
+{
+  if (!hd || !hd->resource)
+    return NULL;
+  return hd->resource->fname;
+}
+
+/* If YES is 1, lock the DB.  Otherwise, unlock it.  Returns an error
+   code if locking failed.  */
+int
+kdb_lock (KDB_HANDLE hd, int yes)
+{
+  int rc;
+  char *err;
+
+  if (yes)
+    /* Lock.  */
+    {
+      rc = sqlite3_exec (hd->resource->db, "begin transaction;",
+                         NULL, NULL, &err);
+      if (rc)
+        {
+          log_error (_("error beginning transaction on KDB database: %s\n"),
+                     err);
+          sqlite3_free (err);
+          return 1;
+        }
+
+      return 0;
+    }
+  else
+    /* Unlock.  */
+    {
+      rc = sqlite3_exec (hd->resource->db, "end transaction;", NULL, NULL, &err);
+      if (rc)
+        {
+          log_error (_("error ending transaction on KDB database: %s\n"),
+                     err);
+          sqlite3_free (err);
+          return 1;
+        }
+
+      return 0;
+    }
+}
+
+static int
+keyblock_cb (void *cookie, int cols, char **values, char **names,
+             sqlite3_stmt *stmt)
+{
+  iobuf_t *iobuf = cookie;
+  const char *data = sqlite3_column_blob (stmt, 0);
+  long long len = sqlite3_column_bytes (stmt, 0);
+
+  (void) cols;
+  (void) values;
+  (void) names;
+
+  assert (! *iobuf);
+  *iobuf = iobuf_temp_with_content (data, len);
+
+  /* Abort to indicate success.  */
+  return 1;
+}
+
+int
+kdb_get_keyblock (KDB_HANDLE hd, iobuf_t *iobuf,
+                  int *pk_no, int *uid_no, u32 **sigstatus)
+{
+  int rc;
+  char *err;
+  sqlite3_stmt *stmt = NULL;
+
+  /* XXX: Fill these in.  */
+  *sigstatus = NULL;
+
+  if (pk_no)
+    *pk_no = 0;
+  if (uid_no)
+    *uid_no = 0;
+
+  if (hd->found.key == -1)
+    /* Got nothing.  */
+    return gpg_error (GPG_ERR_EOF);
+
+  *iobuf = NULL;
+  rc = sqlite3_stepx
+    (hd->resource->db,
+     &stmt, keyblock_cb, iobuf, &err,
+     "select keyblock from primaries where oid = ?",
+     SQLITE_ARG_LONG_LONG, hd->found.key, SQLITE_ARG_END);
+  if (rc == SQLITE_ABORT)
+    /* Success.  */
+    {
+      assert (*iobuf);
+      rc = 0;
+      if (uid_no)
+        *uid_no = hd->found.uid_no;
+      if (pk_no)
+        *pk_no = hd->found.pk_no;
+    }
+  else if (! rc)
+    /* If we don't get an abort, then we didn't find the record.  */
+    rc = gpg_error (GPG_ERR_NOT_FOUND);
+  else
+    {
+      log_error (_("reading keyblock from keydb DB: %s\n"), err);
+      sqlite3_free (err);
+      rc = gpg_error (GPG_ERR_GENERAL);
+    }
+
+  sqlite3_finalize (stmt);
+  return rc;
+}
+
+int
+kdb_update_keyblock (KDB_HANDLE hd, kbnode_t kb,
+                     const void *image, size_t imagelen)
+{
+  (void) hd;
+  (void) kb;
+  (void) image;
+  (void) imagelen;
+
+  log_fatal ("Implement %s.", __func__);
+}
+
+static char *
+strrev (char *str)
+{
+  int i;
+  int l = strlen (str);
+
+  for (i = 0; i < l / 2; i ++)
+    {
+      char t = str[i];
+      str[i] = str[l - 1 - i];
+      str[l - 1 - i] = t;
+    }
+
+  return str;
+}
+
+static char *
+fingerprint_ascii_rev (char *fingerprint_bin, int len)
+{
+  char *fingerprint = xmalloc (2 * len + 1);
+  bin2hex (fingerprint_bin, len, fingerprint);
+  return strrev (fingerprint);
+}
+
+gpg_error_t
+kdb_insert_keyblock (KDB_HANDLE hd, kbnode_t root,
+                     const void *image, size_t imagelen, u32 *sigstatus)
+{
+  PKT_public_key *mainpk = root->pkt->pkt.public_key;
+  char fingerprint_bin[MAX_FINGERPRINT_LEN];
+  size_t fingerprint_bin_len = sizeof (fingerprint_bin);
+  char *fingerprint_rev = NULL;
+
+  int rc;
+  char *err;
+
+  sqlite3_stmt *uid_stmt = NULL;
+  sqlite3_stmt *key_stmt = NULL;
+
+  long long oid;
+  int uid_no;
+  int pk_no;
+  kbnode_t k;
+
+  /* FIXME: Use sigstatus?  */
+  (void) sigstatus;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+
+  /* XXX: If we have a search result (hd->found), are we supposed to
+     replace it even if it isn't for the same key?  */
+  /* See if we are replacing or adding this record to the
+     database.  */
+  fingerprint_from_pk (mainpk, fingerprint_bin, &fingerprint_bin_len);
+  assert (fingerprint_bin_len == sizeof (fingerprint_bin));
+  fingerprint_rev = fingerprint_ascii_rev (fingerprint_bin,
+                                           fingerprint_bin_len);
+
+  oid = -1;
+  rc = sqlite3_stepx
+    (hd->resource->db, NULL, get_unsigned_longs_cb2, &oid, &err,
+     "select oid from primaries where fingerprint_rev = ?;",
+     SQLITE_ARG_STRING, fingerprint_rev, SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error (_("looking up key in keydb DB: %s\n"), err);
+      sqlite3_free (err);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  if (oid != -1)
+    /* This key is already in the DB.  Replace it.  */
+    {
+      rc = sqlite3_exec_printf
+        (hd->resource->db, NULL, NULL, &err,
+         "delete from primaries where oid = %lld;"
+         "delete from keys where primary_key = %lld;"
+         "delete from uids where primary_key = %lld;",
+         oid, oid, oid);
+      if (rc)
+        {
+          log_error (_("updating key in keydb DB: %s\n"), err);
+          sqlite3_free (err);
+          return gpg_error (GPG_ERR_GENERAL);
+        }
+
+      /* Reuse the oid.  So that any extant search won't return the
+         new record.  */
+      rc = sqlite3_stepx
+        (hd->resource->db, NULL, NULL, NULL, &err,
+         "insert into primaries (oid, fingerprint_rev, keyblock)\n"
+         " values (?, ?, ?);",
+         SQLITE_ARG_LONG_LONG, oid,
+         SQLITE_ARG_STRING, fingerprint_rev,
+         SQLITE_ARG_BLOB, image, (long long) imagelen,
+         SQLITE_ARG_END);
+    }
+  else
+    rc = sqlite3_stepx
+      (hd->resource->db, NULL, NULL, NULL, &err,
+       "insert into primaries (fingerprint_rev, keyblock) values (?, ?);",
+       SQLITE_ARG_STRING, fingerprint_rev,
+       SQLITE_ARG_BLOB, image, (long long) imagelen,
+       SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error (_("inserting %s record into keydb DB: %s\n"),
+                 "primary key", err);
+      sqlite3_free (err);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  xfree (fingerprint_rev);
+  fingerprint_rev = NULL;
+
+  oid = sqlite3_last_insert_rowid (hd->resource->db);
+
+  uid_no = 0;
+  pk_no = 0;
+  for (k = root; k; k = k->next)
+    {
+      if (k->pkt->pkttype == PKT_USER_ID)
+        {
+          PKT_user_id *uid = k->pkt->pkt.user_id;
+          const char *user_id = uid->name;
+          char *email = mailbox_from_userid (user_id);
+
+          uid_no ++;
+
+          rc = sqlite3_stepx
+            (hd->resource->db, &uid_stmt, NULL, NULL, &err,
+             "insert into uids (primary_key, uid, email, uid_no)"
+             " values (?, ?, ?, ?);",
+             SQLITE_ARG_LONG_LONG, oid,
+             SQLITE_ARG_STRING, user_id, SQLITE_ARG_STRING, email,
+             SQLITE_ARG_INT, uid_no,
+             SQLITE_ARG_END);
+          xfree (email);
+          if (rc)
+            {
+              log_error (_("inserting %s record into keydb DB: %s\n"),
+                         "uid", err);
+              sqlite3_free (err);
+              return gpg_error (GPG_ERR_GENERAL);
+            }
+        }
+      else if (k->pkt->pkttype == PKT_PUBLIC_KEY
+               || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        {
+          PKT_public_key *pk = k->pkt->pkt.public_key;
+
+          pk_no ++;
+
+          fingerprint_from_pk (pk, fingerprint_bin, &fingerprint_bin_len);
+          assert (fingerprint_bin_len == sizeof (fingerprint_bin));
+          fingerprint_rev = fingerprint_ascii_rev (fingerprint_bin,
+                                                   fingerprint_bin_len);
+
+          rc = sqlite3_stepx
+            (hd->resource->db, &key_stmt, NULL, NULL, &err,
+             "insert into keys (primary_key, fingerprint_rev, pk_no)"
+             " values (?, ?, ?);",
+             SQLITE_ARG_LONG_LONG, oid,
+             SQLITE_ARG_STRING, fingerprint_rev,
+             SQLITE_ARG_INT, pk_no,
+             SQLITE_ARG_END);
+
+          xfree (fingerprint_rev);
+          fingerprint_rev = NULL;
+
+          if (rc)
+            {
+              log_error (_("inserting %s record into keydb DB: %s\n"),
+                         "key", err);
+              sqlite3_free (err);
+              return gpg_error (GPG_ERR_GENERAL);
+            }
+        }
+    }
+
+  sqlite3_finalize (uid_stmt);
+  sqlite3_finalize (key_stmt);
+
+  return 0;
+}
+
+int
+kdb_delete (KDB_HANDLE hd)
+{
+  int rc;
+  char *err;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (hd->found.key == -1)
+    /* No search result.  */
+    return gpg_error (GPG_ERR_NOTHING_FOUND);
+
+  rc = sqlite3_exec_printf
+    (hd->resource->db, NULL, NULL, &err,
+     "begin transaction;\n"
+     "delete from keys where primary = %d;\n"
+     "delete from uids where primary = %d;\n"
+     "delete from primaries where oid = %d;\n"
+     "end transaction;\n",
+     hd->found.key, hd->found.key, hd->found.key);
+  if (rc)
+    {
+      log_error (_("error deleting key from kdb database: %s\n"), err);
+      sqlite3_free (err);
+      rc = gpg_error (GPG_ERR_GENERAL);
+    }
+
+  return rc;
+}
+
+int
+kdb_search_reset (KDB_HANDLE hd)
+{
+  hd->key = -1;
+  hd->eof = 0;
+  return 0;
+}
+
+int
+kdb_search (KDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+            size_t ndesc, size_t *descindex)
+{
+  int n;
+  char *where_uid = NULL;
+  char *where_key = NULL;
+  char *text;
+  int anyskip = 0;
+  /* This must match the number of items that are returned.  */
+  unsigned long int result[3];
+  int rc = 0;
+  char *err = NULL;
+  char *sql = NULL;
+
+  result[0] = -1;
+
+  /* If we are doing a scan, just get the next record.  */
+  for (n = 0; n < ndesc; n ++)
+    {
+      if (desc[n].mode == KEYDB_SEARCH_MODE_FIRST)
+        {
+          kdb_search_reset (hd);
+          rc = sqlite3_exec (hd->resource->db,
+                             "select min(oid) from primaries",
+                             get_unsigned_longs_cb, result, &err);
+        }
+      else if (desc[n].mode == KEYDB_SEARCH_MODE_NEXT)
+        rc = sqlite3_exec_printf
+          (hd->resource->db, get_unsigned_longs_cb, result, &err,
+           "select oid from primaries where oid > %lld order by oid limit 1",
+           hd->key);
+      else
+        continue;
+
+      if (rc)
+        {
+          log_fatal ("error getting next record: %s\n", err);
+          sqlite3_free (err);
+        }
+      else if (result[0] == -1)
+        /* EOF.  */
+        hd->eof = 1;
+      else
+        {
+          hd->key = hd->found.key = result[0];
+          hd->found.pk_no = hd->found.uid_no = 0;
+        }
+
+      goto out;
+    }
+
+  if (hd->eof)
+    /* We're at the end of the file.  There is nothing else to get.  */
+    return gpg_error (GPG_ERR_EOF);
+
+#define ADD_TERM(thing, op, fmt, ...) do {              \
+    char *t = sqlite3_mprintf                           \
+      ("%s%s("fmt")",                                   \
+       thing ? thing : "", thing ? "\n "op" " : "",     \
+       ##__VA_ARGS__);                                  \
+    sqlite3_free (thing);                               \
+    thing = t;                                          \
+  } while (0)
+#define O(thing, fmt, ...) ADD_TERM(thing, "OR", fmt, ##__VA_ARGS__)
+#define A(thing, fmt, ...) ADD_TERM(thing, "AND", fmt, ##__VA_ARGS__)
+
+  if (descindex)
+    log_fatal ("Implement descindex\n");
+
+  for (n = 0; n < ndesc; n ++)
+    {
+      KEYDB_SEARCH_DESC *d = &desc[n];
+
+      switch (d->mode)
+        {
+        case KEYDB_SEARCH_MODE_EXACT:
+          O(where_uid, "uids.uid = %Q", desc[n].u.name);
+          break;
+
+        case KEYDB_SEARCH_MODE_SUBSTR:
+        case KEYDB_SEARCH_MODE_MAIL:
+        case KEYDB_SEARCH_MODE_MAILSUB:
+        case KEYDB_SEARCH_MODE_MAILEND:
+          {
+            char *escaped = xmalloc (1 + 2 * strlen (d->u.name) + 1 + 1);
+            int i, j = 0;
+
+            if (d->mode == KEYDB_SEARCH_MODE_SUBSTR
+                || d->mode == KEYDB_SEARCH_MODE_MAILSUB
+                || d->mode == KEYDB_SEARCH_MODE_MAILEND)
+              escaped[j ++] = '%';
+
+            for (i = 0; i < strlen (d->u.name); i ++)
+              {
+                if (d->u.name[i] == '%' || d->u.name[i] == '_'
+                    || d->u.name[i] == '\'' || d->u.name[i] == '\\')
+                  escaped[j ++] = '\\';
+                escaped[j ++] = d->u.name[i];
+              }
+
+            if (d->mode == KEYDB_SEARCH_MODE_SUBSTR
+                || d->mode == KEYDB_SEARCH_MODE_MAILSUB)
+              escaped[j ++] = '%';
+
+            escaped[j] = 0;
+
+            O(where_uid, "uids.%s like %Q",
+              d->mode == KEYDB_SEARCH_MODE_SUBSTR ? "uid" : "email",
+              escaped);
+          }
+          break;
+
+
+        case KEYDB_SEARCH_MODE_WORDS:
+          log_fatal ("Implement me!\n");
+          break;
+
+
+        case KEYDB_SEARCH_MODE_SHORT_KID:
+          text = bin2hex (&d->u.kid[1], 4, NULL);
+          /* Fall through.  */
+
+        case KEYDB_SEARCH_MODE_LONG_KID:
+          if (d->mode == KEYDB_SEARCH_MODE_LONG_KID)
+            {
+              text = xmalloc (17);
+              bin2hex (&d->u.kid[1], 4, text);
+              bin2hex (&d->u.kid[0], 4, &text[strlen (text)]);
+              strrev (text);
+            }
+
+          O(where_key, "keys.fingerprint_rev like '%s%%'", text);
+          xfree (text);
+          break;
+
+        case KEYDB_SEARCH_MODE_FPR16:
+          if (d->mode == KEYDB_SEARCH_MODE_FPR16)
+            text = bin2hex (d->u.fpr, 16, NULL);
+          /* Fall through.  */
+
+        case KEYDB_SEARCH_MODE_FPR20:
+        case KEYDB_SEARCH_MODE_FPR:
+          if (d->mode == KEYDB_SEARCH_MODE_FPR20
+              || d->mode == KEYDB_SEARCH_MODE_FPR)
+            text = bin2hex (d->u.fpr, 20, NULL);
+
+          strrev (text);
+          O(where_key, "keys.fingerprint_rev = '%s'", text);
+          xfree (text);
+          break;
+
+        case KEYDB_SEARCH_MODE_FIRST:
+        case KEYDB_SEARCH_MODE_NEXT:
+          /* Already handled above.  */
+          break;
+
+        default:
+          break;
+        }
+
+      if (d->skipfnc)
+        anyskip = 1;
+    }
+
+  if (anyskip)
+    log_fatal ("Implement anyskip.");
+
+  assert (where_uid || where_key);
+  if (where_uid && where_key)
+    sql = sqlite3_mprintf
+      ("select keys.primary_key, keys.pk_no, uids.uid_no\n"
+       " from primaries\n"
+       " left join keys on primaries.oid = keys.primary_key\n"
+       " left join uids on primaries.oid = uids.primary_key\n"
+       " where %s%lld and (%s and %s)\n"
+       " order by keys.primary_key, keys.pk_no, uids.uid_no\n"
+       " limit 1\n",
+       hd->key == -1 ? "" : "keys.primary_key > ", hd->key,
+       where_uid, where_key);
+  else if (where_key)
+    sql = sqlite3_mprintf
+      ("select primary_key, pk_no\n"
+       " from keys\n"
+       " where %s%lld and (%s)\n"
+       " order by primary_key, pk_no\n"
+       " limit 1;\n",
+       hd->key == -1 ? "" : "primary_key > ", hd->key, where_key);
+  else
+    sql = sqlite3_mprintf
+      ("select primary_key, uid_no\n"
+       " from uids\n"
+       " where %s%lld and (%s)\n"
+       " order by primary_key, uid_no\n"
+       " limit 1;\n",
+       hd->key == -1 ? "" : "primary_key > ", hd->key, where_uid);
+#if 0
+  log_info("Running '%s'\n", sql);
+#endif
+  rc = sqlite3_exec (hd->resource->db, sql, get_unsigned_longs_cb, result, &err);
+  if (rc)
+    {
+      log_fatal ("error search DB: %s\n", err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  if (result[0] == -1)
+    /* No result.  */
+    hd->eof = 1;
+  else
+    {
+      hd->key = result[0];
+      hd->found.key = result[0];
+      hd->found.pk_no = result[1];
+      hd->found.uid_no = result[2];
+    }
+
+ out:
+  sqlite3_free (sql);
+  sqlite3_free (where_uid);
+  sqlite3_free (where_key);
+
+  if (rc)
+    return gpg_error (GPG_ERR_GENERAL);
+  if (hd->eof)
+    {
+      hd->key = -1;
+      return gpg_error (GPG_ERR_EOF);
+    }
+
+  return 0;
+}
diff --git a/g10/kdb.h b/g10/kdb.h
new file mode 100644
index 0000000..55e6962
--- /dev/null
+++ b/g10/kdb.h
@@ -0,0 +1,29 @@
+#ifndef GNUPG_KDB_H
+#define GNUPG_KDB_H
+
+#include "keydb.h"
+
+typedef struct keydb_handle *KDB_HANDLE;
+
+gpg_error_t kdb_register_file (const char *fname, int read_only, void **ptr);
+int kdb_is_writable (void *token);
+
+KDB_HANDLE kdb_new (void *token);
+void kdb_release (KDB_HANDLE hd);
+void kdb_push_found_state (KDB_HANDLE hd);
+void kdb_pop_found_state (KDB_HANDLE hd);
+const char *kdb_get_resource_name (KDB_HANDLE hd);
+int kdb_lock (KDB_HANDLE hd, int yes);
+int kdb_get_keyblock (KDB_HANDLE hd, iobuf_t *iobuf,
+                      int *pk_no, int *uid_no, u32 **sigstatus);
+int kdb_update_keyblock (KDB_HANDLE hd, kbnode_t kb,
+                         const void *image, size_t imagelen);
+gpg_error_t kdb_insert_keyblock (KDB_HANDLE hd, kbnode_t kb,
+                                 const void *image, size_t imagelen,
+                                 u32 *sigstatus);
+int kdb_delete (KDB_HANDLE hd);
+int kdb_search_reset (KDB_HANDLE hd);
+int kdb_search (KDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+                size_t ndesc, size_t *descindex);
+
+#endif
diff --git a/g10/keydb.c b/g10/keydb.c
index bcafe90..fb79377 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -37,6 +37,7 @@
 #include "../kbx/keybox.h"
 #include "keydb.h"
 #include "i18n.h"
+#include "kdb.h"
 
 static int active_handles;
 
@@ -44,7 +45,8 @@ typedef enum
   {
     KEYDB_RESOURCE_TYPE_NONE = 0,
     KEYDB_RESOURCE_TYPE_KEYRING,
-    KEYDB_RESOURCE_TYPE_KEYBOX
+    KEYDB_RESOURCE_TYPE_KEYBOX,
+    KEYDB_RESOURCE_TYPE_KEYDB
   } KeydbResourceType;
 #define MAX_KEYDB_RESOURCES 40
 
@@ -54,6 +56,7 @@ struct resource_item
   union {
     KEYRING_HANDLE kr;
     KEYBOX_HANDLE kb;
+    KDB_HANDLE kdb;
   } u;
   void *token;
 };
@@ -251,13 +254,14 @@ keyblock_cache_clear (struct keydb_handle *hd)
 /* Handle the creation of a keyring or a keybox if it does not yet
    exist.  Take into account that other processes might have the
    keyring/keybox already locked.  This lock check does not work if
-   the directory itself is not yet available.  If IS_BOX is true the
-   filename is expected to refer to a keybox.  If FORCE_CREATE is true
-   the keyring or keybox will be created.
+   the directory itself is not yet available.  RT is the type of
+   resource being created.  If FORCE_CREATE is true the keyring or
+   keybox will be created.
 
    Return 0 if it is okay to access the specified file.  */
 static int
-maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
+maybe_create_resource (char *filename, KeydbResourceType rt,
+                             int force_create)
 {
   dotlock_t lockhd = NULL;
   IOBUF iobuf;
@@ -361,12 +365,25 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
   if (!iobuf)
     {
       rc = gpg_error_from_syserror ();
-      if (is_box)
-        log_error (_("error creating keybox '%s': %s\n"),
-                   filename, gpg_strerror (rc));
-      else
-        log_error (_("error creating keyring '%s': %s\n"),
-                   filename, gpg_strerror (rc));
+      switch (rt)
+        {
+        case KEYDB_RESOURCE_TYPE_NONE:
+          log_fatal ("Bad value for resource type: %d\n", rt);
+          break;
+
+        case KEYDB_RESOURCE_TYPE_KEYRING:
+          log_error (_("error creating keyring '%s': %s\n"),
+                     filename, gpg_strerror (rc));
+          break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          log_error (_("error creating keybox '%s': %s\n"),
+                     filename, gpg_strerror (rc));
+          break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          log_error (_("error creating keydb '%s': %s\n"),
+                     filename, gpg_strerror (rc));
+          break;
+        }
       goto leave;
     }
 
@@ -376,7 +393,7 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
 
   /* Make sure that at least one record is in a new keybox file, so
      that the detection magic will work the next time it is used.  */
-  if (is_box)
+  if (rt == KEYDB_RESOURCE_TYPE_KEYBOX)
     {
       FILE *fp = fopen (filename, "w");
       if (!fp)
@@ -388,22 +405,29 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
         }
       if (rc)
         {
-          if (is_box)
-            log_error (_("error creating keybox '%s': %s\n"),
-                       filename, gpg_strerror (rc));
-          else
-            log_error (_("error creating keyring '%s': %s\n"),
-                       filename, gpg_strerror (rc));
+          log_error (_("error creating keybox '%s': %s\n"),
+                     filename, gpg_strerror (rc));
           goto leave;
         }
     }
 
   if (!opt.quiet)
     {
-      if (is_box)
-        log_info (_("keybox '%s' created\n"), filename);
-      else
-        log_info (_("keyring '%s' created\n"), filename);
+      switch (rt)
+        {
+        case KEYDB_RESOURCE_TYPE_NONE:
+          log_fatal ("Bad value for resource type: %d\n", rt);
+          break;
+        case KEYDB_RESOURCE_TYPE_KEYRING:
+          log_info (_("keyring '%s' created\n"), filename);
+          break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          log_info (_("keybox '%s' created\n"), filename);
+          break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          log_info (_("keydb '%s' created\n"), filename);
+          break;
+        }
     }
 
   rc = 0;
@@ -445,6 +469,8 @@ rt_from_file (const char *filename, int *r_found, int *r_openpgp)
         {
           if (magic == 0x13579ace || magic == 0xce9a5713)
             ; /* GDBM magic - not anymore supported. */
+          else if (memcmp (&magic, "SQLi", 4) == 0)
+            rt = KEYDB_RESOURCE_TYPE_KEYDB;
           else if (fread (&verbuf, 4, 1, fp) == 1
                    && verbuf[0] == 1
                    && fread (&magic, 4, 1, fp) == 1
@@ -497,6 +523,11 @@ keydb_add_resource (const char *url, unsigned int flags)
       rt = KEYDB_RESOURCE_TYPE_KEYBOX;
       resname += 10;
     }
+  else if (strlen (resname) > 10 && !strncmp (resname, "gnupg-kdb:", 10) )
+    {
+      rt = KEYDB_RESOURCE_TYPE_KEYDB;
+      resname += 10;
+    }
 #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
   else if (strchr (resname, ':'))
     {
@@ -600,7 +631,8 @@ keydb_add_resource (const char *url, unsigned int flags)
       goto leave;
 
     case KEYDB_RESOURCE_TYPE_KEYRING:
-      rc = maybe_create_keyring_or_box (filename, 0, create);
+      rc = maybe_create_resource (filename, KEYDB_RESOURCE_TYPE_KEYRING,
+                                  create);
       if (rc)
         goto leave;
 
@@ -630,7 +662,8 @@ keydb_add_resource (const char *url, unsigned int flags)
 
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       {
-        rc = maybe_create_keyring_or_box (filename, 1, create);
+        rc = maybe_create_resource (filename, KEYDB_RESOURCE_TYPE_KEYBOX,
+                                    create);
         if (rc)
           goto leave;
 
@@ -665,6 +698,36 @@ keydb_add_resource (const char *url, unsigned int flags)
       }
       break;
 
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      {
+        rc = maybe_create_resource (filename, KEYDB_RESOURCE_TYPE_KEYDB, create);
+        if (rc)
+          goto leave;
+
+        rc = kdb_register_file (filename, read_only, &token);
+        if (rc == 0)
+          {
+            if (used_resources >= MAX_KEYDB_RESOURCES)
+              rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
+            else
+              {
+                /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
+                /*   primary_keyring = token; */
+                all_resources[used_resources].type = rt;
+                all_resources[used_resources].u.kb = NULL; /* Not used here */
+                all_resources[used_resources].token = token;
+
+                used_resources++;
+              }
+          }
+
+        /* XXX: How to mark this as a primary if it was already
+           registered.  */
+        /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
+        /*   primary_keyring = token; */
+      }
+      break;
+
       default:
 	log_error ("resource type of '%s' not supported\n", url);
 	rc = gpg_error (GPG_ERR_GENERAL);
@@ -730,6 +793,14 @@ keydb_new (void)
 	    die = 1;
           j++;
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          hd->active[j].type   = all_resources[i].type;
+          hd->active[j].token  = all_resources[i].token;
+          hd->active[j].u.kdb  = kdb_new (all_resources[i].token);
+          if (!hd->active[j].u.kdb)
+	    die = 1;
+          j++;
+          break;
         }
     }
   hd->used = j;
@@ -769,6 +840,9 @@ keydb_release (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           keybox_release (hd->active[i].u.kb);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          kdb_release (hd->active[i].u.kdb);
+          break;
         }
     }
 
@@ -811,6 +885,9 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       s = keybox_get_resource_name (hd->active[idx].u.kb);
       break;
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      s = kdb_get_resource_name (hd->active[idx].u.kdb);
+      break;
     }
 
   return s? s: "";
@@ -842,6 +919,9 @@ lock_all (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           rc = keybox_lock (hd->active[i].u.kb, 1);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          rc = kdb_lock (hd->active[i].u.kdb, 1);
+          break;
         }
     }
 
@@ -860,6 +940,9 @@ lock_all (KEYDB_HANDLE hd)
             case KEYDB_RESOURCE_TYPE_KEYBOX:
               rc = keybox_lock (hd->active[i].u.kb, 0);
               break;
+            case KEYDB_RESOURCE_TYPE_KEYDB:
+              rc = kdb_lock (hd->active[i].u.kdb, 0);
+              break;
             }
         }
     }
@@ -890,6 +973,9 @@ unlock_all (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           keybox_lock (hd->active[i].u.kb, 0);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          kdb_lock (hd->active[i].u.kdb, 0);
+          break;
         }
     }
   hd->locked = 0;
@@ -919,6 +1005,9 @@ keydb_push_found_state (KEYDB_HANDLE hd)
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       keybox_push_found_state (hd->active[hd->found].u.kb);
       break;
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      kdb_push_found_state (hd->active[hd->found].u.kdb);
+      break;
     }
 
   hd->saved_found = hd->found;
@@ -947,6 +1036,9 @@ keydb_pop_found_state (KEYDB_HANDLE hd)
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       keybox_pop_found_state (hd->active[hd->found].u.kb);
       break;
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      kdb_pop_found_state (hd->active[hd->found].u.kdb);
+      break;
     }
 }
 
@@ -1192,6 +1284,23 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
           }
       }
       break;
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      {
+        iobuf_t iobuf;
+        u32 *sigstatus;
+        int pk_no, uid_no;
+
+        err = kdb_get_keyblock (hd->active[hd->found].u.kdb, &iobuf,
+                                &pk_no, &uid_no, &sigstatus);
+        if (!err)
+          {
+            err = parse_keyblock_image (iobuf, pk_no, uid_no, sigstatus,
+                                        ret_kb);
+            xfree (sigstatus);
+            iobuf_close (iobuf);
+          }
+        break;
+      }
     }
 
   if (hd->keyblock_cache.state != KEYBLOCK_CACHE_FILLED)
@@ -1337,6 +1446,20 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
           }
       }
       break;
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      {
+        iobuf_t iobuf;
+
+        err = build_keyblock_image (kb, &iobuf, NULL);
+        if (!err)
+          {
+            err = kdb_update_keyblock (hd->active[hd->found].u.kdb, kb,
+                                       iobuf_get_temp_buffer (iobuf),
+                                       iobuf_get_temp_length (iobuf));
+            iobuf_close (iobuf);
+          }
+      }
+      break;
     }
 
   unlock_all (hd);
@@ -1398,6 +1521,23 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
           }
       }
       break;
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      {
+        iobuf_t iobuf;
+        u32 *sigstatus;
+
+        err = build_keyblock_image (kb, &iobuf, &sigstatus);
+        if (!err)
+          {
+            err = kdb_insert_keyblock (hd->active[idx].u.kdb, kb,
+                                       iobuf_get_temp_buffer (iobuf),
+                                       iobuf_get_temp_length (iobuf),
+                                       sigstatus);
+            xfree (sigstatus);
+            iobuf_close (iobuf);
+          }
+      }
+      break;
     }
 
   unlock_all (hd);
@@ -1437,6 +1577,9 @@ keydb_delete_keyblock (KEYDB_HANDLE hd)
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       rc = keybox_delete (hd->active[hd->found].u.kb);
       break;
+    case KEYDB_RESOURCE_TYPE_KEYDB:
+      rc = kdb_delete (hd->active[hd->found].u.kdb);
+      break;
     }
 
   unlock_all (hd);
@@ -1491,6 +1634,10 @@ keydb_locate_writable (KEYDB_HANDLE hd)
           if (keybox_is_writable (hd->active[hd->current].token))
             return 0; /* found (hd->current is set to it) */
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          if (kdb_is_writable (hd->active[hd->current].token))
+            return 0; /* found (hd->current is set to it) */
+          break;
         }
     }
 
@@ -1519,6 +1666,9 @@ keydb_rebuild_caches (int noisy)
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           /* N/A.  */
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          /* N/A.  */
+          break;
         }
     }
 }
@@ -1564,6 +1714,9 @@ keydb_search_reset (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           rc = keybox_search_reset (hd->active[i].u.kb);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          rc = kdb_search_reset (hd->active[i].u.kdb);
+          break;
         }
     }
   hd->is_reset = 1;
@@ -1682,6 +1835,10 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
                               ndesc, KEYBOX_BLOBTYPE_PGP,
                               descindex, &hd->skipped_long_blobs);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYDB:
+          rc = kdb_search (hd->active[hd->current].u.kdb, desc,
+                           ndesc, descindex);
+          break;
         }
       if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
         {

-----------------------------------------------------------------------

Summary of changes:
 Makefile.am                         |    2 +-
 README                              |    2 +-
 agent/ChangeLog-2011                |    2 +-
 agent/command.c                     |    2 +-
 autogen.sh                          |    1 +
 common/ChangeLog-2011               |    2 +-
 common/Makefile.am                  |   34 +-
 common/mkdir_p.c                    |   17 +-
 common/srv.c                        |  333 ---------
 common/srv.h                        |   62 --
 common/status.h                     |    2 +
 common/ttyio.c                      |    2 +-
 common/util.h                       |    3 +
 configure.ac                        |  169 +++--
 dirmngr/Makefile.am                 |   39 +-
 dirmngr/crlcache.c                  |    3 +-
 dirmngr/crlfetch.c                  |   16 +-
 dirmngr/dirmngr.c                   |   23 +-
 dirmngr/dirmngr.h                   |    4 +-
 dirmngr/dns-cert.c                  |  433 ------------
 dirmngr/dns-stuff.c                 | 1265 +++++++++++++++++++++++++++++++++++
 dirmngr/{dns-cert.h => dns-stuff.h} |   80 ++-
 {common => dirmngr}/http.c          |  311 ++++-----
 {common => dirmngr}/http.h          |    0
 dirmngr/ks-engine-hkp.c             |  207 +++---
 dirmngr/ks-engine-ldap.c            |   12 +-
 dirmngr/ks-engine.h                 |    2 +-
 dirmngr/ocsp.c                      |    4 +-
 dirmngr/server.c                    |   11 +-
 dirmngr/t-dns-cert.c                |   93 ---
 dirmngr/t-dns-stuff.c               |  276 ++++++++
 {common => dirmngr}/t-http.c        |    4 +
 {common => dirmngr}/tls-ca.pem      |    0
 doc/Makefile.am                     |    4 +-
 doc/dirmngr.texi                    |   10 +-
 doc/gpg.texi                        |   25 +-
 doc/gpgv.texi                       |    8 +
 doc/tools.texi                      |    2 +-
 g10/Makefile.am                     |   19 +-
 g10/call-dirmngr.c                  |    4 +-
 g10/card-util.c                     |    1 +
 g10/dirmngr-conf.skel               |    3 +
 g10/gpg.c                           |   64 +-
 g10/gpgv.c                          |   22 +-
 g10/kdb.c                           |  938 ++++++++++++++++++++++++++
 g10/kdb.h                           |   29 +
 g10/keydb.c                         |  208 +++++-
 g10/keyedit.c                       |    2 +
 g10/keylist.c                       |   10 +
 g10/keyring.h                       |    1 -
 g10/keyserver.c                     |    4 +-
 g10/main.h                          |   28 +-
 g10/mainproc.c                      |   41 +-
 g10/misc.c                          |   70 +-
 g10/options.h                       |    6 +-
 g10/packet.h                        |   16 +-
 g10/revoke.c                        |   13 +-
 g10/sig-check.c                     |  312 +++++++--
 g10/sqlite.c                        |  252 +++++++
 g10/sqlite.h                        |   62 ++
 g10/tdbio.c                         |    2 +-
 g10/test-stubs.c                    |   15 +-
 g10/tofu.c                          | 1207 ++++++++++++++++++++++-----------
 g10/tofu.h                          |   14 +-
 g10/trustdb.c                       |  105 ++-
 g10/trustdb.h                       |    9 +-
 kbx/keybox-search.c                 |    2 +-
 po/POTFILES.in                      |    2 +-
 sm/certreqgen.c                     |   77 ++-
 tests/openpgp/Makefile.am           |    5 +-
 tools/gpgconf-comp.c                |    4 +-
 71 files changed, 4977 insertions(+), 2035 deletions(-)
 delete mode 100644 common/srv.c
 delete mode 100644 common/srv.h
 delete mode 100644 dirmngr/dns-cert.c
 create mode 100644 dirmngr/dns-stuff.c
 rename dirmngr/{dns-cert.h => dns-stuff.h} (52%)
 rename {common => dirmngr}/http.c (92%)
 rename {common => dirmngr}/http.h (100%)
 delete mode 100644 dirmngr/t-dns-cert.c
 create mode 100644 dirmngr/t-dns-stuff.c
 rename {common => dirmngr}/t-http.c (99%)
 rename {common => dirmngr}/tls-ca.pem (100%)
 create mode 100644 g10/kdb.c
 create mode 100644 g10/kdb.h
 create mode 100644 g10/sqlite.c
 create mode 100644 g10/sqlite.h


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list