[git] GnuPG - branch, neal/next, updated. gnupg-2.1.9-89-g3322631
by Neal H. Walfield
cvs at cvs.gnupg.org
Thu Oct 29 10:51:23 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 692fe5f7ac301d828085f7685e451fec3f6d06bb (commit)
via 3322631fc9c1d476c80f8d33f1987663c73289ee (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 (692fe5f7ac301d828085f7685e451fec3f6d06bb)
\
N -- N -- N (3322631fc9c1d476c80f8d33f1987663c73289ee)
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 3322631fc9c1d476c80f8d33f1987663c73289ee
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..6a97177
--- /dev/null
+++ b/g10/kdb.c
@@ -0,0 +1,956 @@
+#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 ++)
+ {
+ if (! argv[i])
+ values[i] = 0;
+ else
+ {
+ 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 coalesce(min(oid), -1) 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];
+ if (where_key && where_uid)
+ {
+ hd->found.pk_no = result[1];
+ hd->found.uid_no = result[2];
+ }
+ else if (where_key)
+ {
+ hd->found.pk_no = result[1];
+ hd->found.uid_no = 0;
+ }
+ else
+ {
+ hd->found.pk_no = 0;
+ hd->found.uid_no = result[1];
+ }
+ }
+
+ 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:
g10/kdb.c | 34 ++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)
hooks/post-receive
--
The GNU Privacy Guard
http://git.gnupg.org
More information about the Gnupg-commits
mailing list