gpg: New option --use-keyboxd.
authorWerner Koch <wk@gnupg.org>
Mon, 9 Sep 2019 12:34:09 +0000 (14:34 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 9 Sep 2019 13:01:47 +0000 (15:01 +0200)
* g10/gpg.c (oUseKeyboxd,oKeyboxdProgram): New consts.
(opts): New options --use-keyboxd and --keyboxd-program.
(main): Implement them.
* g10/keydb.c: Move some defs out to ...
* g10/keydb-private.h: new file.
* g10/keydb.c: prefix function names with "internal" and move original
functions to ...
* g10/call-keyboxd.c: new file.  Divert to the internal fucntion if
--use-keyboxd is used.  Add a CTRL arg to most fucntions and change
all callers.
* g10/Makefile.am (common_source): Add new files.
(noinst_PROGRAMS): Do bot build gpgcompose.
--

Note that this is just the framework with only a basic implementation
of searching via keyboxd.

Signed-off-by: Werner Koch <wk@gnupg.org>
26 files changed:
g10/Makefile.am
g10/call-keyboxd.c [new file with mode: 0644]
g10/delkey.c
g10/export.c
g10/getkey.c
g10/gpg.c
g10/gpg.h
g10/gpgcompose.c
g10/import.c
g10/keydb-private.h [new file with mode: 0644]
g10/keydb.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keylist.c
g10/keyserver.c
g10/main.h
g10/misc.c
g10/options.h
g10/photoid.c
g10/revoke.c
g10/sign.c
g10/t-keydb-get-keyblock.c
g10/t-keydb.c
g10/tofu.c
g10/trustdb.c

index 884b474..1404014 100644 (file)
@@ -50,9 +50,9 @@ noinst_PROGRAMS = gpg
 if !HAVE_W32CE_SYSTEM
 noinst_PROGRAMS += gpgv
 endif
-if MAINTAINER_MODE
-noinst_PROGRAMS += gpgcompose
-endif
+#if MAINTAINER_MODE
+#noinst_PROGRAMS += gpgcompose
+#endif
 noinst_PROGRAMS += $(module_tests)
 TESTS = $(module_tests)
 TESTS_ENVIRONMENT = \
@@ -99,7 +99,10 @@ common_source =  \
              filter.h          \
              free-packet.c     \
              getkey.c          \
-             keydb.c keydb.h    \
+             keydb.h           \
+             keydb-private.h   \
+              call-keyboxd.c    \
+             keydb.c           \
              keyring.c keyring.h \
              seskey.c          \
              kbnode.c          \
@@ -160,7 +163,7 @@ gpg_SOURCES  = gpg.c \
        keyedit.c keyedit.h     \
        $(gpg_sources)
 
-gpgcompose_SOURCES  = gpgcompose.c  $(gpg_sources)
+#gpgcompose_SOURCES  = gpgcompose.c  $(gpg_sources)
 gpgv_SOURCES = gpgv.c           \
              $(common_source)  \
              verify.c
@@ -179,29 +182,32 @@ gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
             $(LIBICONV) $(resource_objs) $(extra_sys_libs)
 gpg_LDFLAGS = $(extra_bin_ldflags)
 gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
-              $(GPG_ERROR_LIBS) \
+             $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(resource_objs) $(extra_sys_libs)
 gpgv_LDFLAGS = $(extra_bin_ldflags)
 
-gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
-             $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
-            $(LIBICONV) $(resource_objs) $(extra_sys_libs)
-gpgcompose_LDFLAGS = $(extra_bin_ldflags)
+#gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+#             $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
+#           $(LIBICONV) $(resource_objs) $(extra_sys_libs)
+#gpgcompose_LDFLAGS = $(extra_bin_ldflags)
 
 t_common_ldadd =
 module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter
 t_rmd160_SOURCES = t-rmd160.c rmd160.c
 t_rmd160_LDADD = $(t_common_ldadd)
 t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source)
-t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
+t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
+              $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(t_common_ldadd)
 t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \
              $(common_source)
-t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
+t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
+              $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(t_common_ldadd)
 t_stutter_SOURCES = t-stutter.c test-stubs.c \
              $(common_source)
-t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
+t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
+             $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(t_common_ldadd)
 
 
diff --git a/g10/call-keyboxd.c b/g10/call-keyboxd.c
new file mode 100644 (file)
index 0000000..f05a9e8
--- /dev/null
@@ -0,0 +1,842 @@
+/* call-keyboxd.c - Access to the keyboxd storage server
+ * Copyright (C) 2019  g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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 <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include "gpg.h"
+#include <assuan.h>
+#include "../common/util.h"
+#include "../common/membuf.h"
+#include "options.h"
+#include "../common/i18n.h"
+#include "../common/asshelp.h"
+#include "../common/status.h"
+#include "keydb.h"
+
+#include "keydb-private.h"  /* For struct keydb_handle_s */
+
+
+/* Data used to keep track of keybox daemon sessions.  This allows us
+ * to use several sessions with the keyboxd and also to re-use already
+ * established sessions.  Note that gpg.h defines the type
+ * keyboxd_local_t for this structure. */
+struct keyboxd_local_s
+{
+  /* Link to other keyboxd contexts which are used simultaneously.  */
+  struct keyboxd_local_s *next;
+
+  /* The active Assuan context. */
+  assuan_context_t ctx;
+
+  /* This flag set while an operation is running on this context.  */
+  unsigned int is_active : 1;
+
+  /* This flag is set to record that the standard per session init has
+   * been done.  */
+  unsigned int per_session_init_done : 1;
+};
+
+
+
+\f
+/* Deinitialize all session resources pertaining to the keyboxd.  */
+void
+gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
+{
+  keyboxd_local_t kbl;
+
+  while ((kbl = ctrl->keyboxd_local))
+    {
+      ctrl->keyboxd_local = kbl->next;
+      if (kbl->is_active)
+        log_error ("oops: trying to cleanup an active keyboxd context\n");
+      else
+        assuan_release (kbl->ctx);
+      xfree (kbl);
+    }
+}
+
+
+/* Print a warning if the server's version number is less than our
+   version number.  Returns an error code on a connection problem.  */
+static gpg_error_t
+warn_version_mismatch (assuan_context_t ctx, const char *servername)
+{
+  gpg_error_t err;
+  char *serverversion;
+  const char *myversion = strusage (13);
+
+  err = get_assuan_server_version (ctx, 0, &serverversion);
+  if (err)
+    log_error (_("error getting version from '%s': %s\n"),
+               servername, gpg_strerror (err));
+  else if (compare_version_strings (serverversion, myversion) < 0)
+    {
+      char *warn;
+
+      warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
+                           servername, serverversion, myversion);
+      if (!warn)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          log_info (_("WARNING: %s\n"), warn);
+          if (!opt.quiet)
+            {
+              log_info (_("Note: Outdated servers may lack important"
+                          " security fixes.\n"));
+              log_info (_("Note: Use the command \"%s\" to restart them.\n"),
+                        "gpgconf --kill all");
+            }
+
+          write_status_strings (STATUS_WARNING, "server_version_mismatch 0",
+                                " ", warn, NULL);
+          xfree (warn);
+        }
+    }
+  xfree (serverversion);
+  return err;
+}
+
+
+/* Connect to the keybox daemon and launch it if necessary.  Handle
+ * the server's initial greeting and set global options.  Returns a
+ * new assuan context or an error.  */
+static gpg_error_t
+create_new_context (ctrl_t ctrl, assuan_context_t *r_ctx)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+
+  *r_ctx = NULL;
+
+  err = start_new_keyboxd (&ctx,
+                           GPG_ERR_SOURCE_DEFAULT,
+                           opt.keyboxd_program,
+                           opt.autostart, opt.verbose, DBG_IPC,
+                           NULL, ctrl);
+  if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_KEYBOXD)
+    {
+      static int shown;
+
+      if (!shown)
+        {
+          shown = 1;
+          log_info (_("no keyboxd running in this session\n"));
+        }
+    }
+  else if (!err && !(err = warn_version_mismatch (ctx, KEYBOXD_NAME)))
+    {
+      /* Place to emit global options.  */
+    }
+
+  if (err)
+    assuan_release (ctx);
+  else
+    *r_ctx = ctx;
+
+  return err;
+}
+
+
+/* Get a context for accessing keyboxd.  If no context is available a
+ * new one is created and if necessary keyboxd is started.  On success
+ * an assuan context is stored at R_CTX.  This context may only be
+ * released by means of close_context.  Note that NULL is stored at
+ * R_CTX on error.  */
+static gpg_error_t
+open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
+{
+  gpg_error_t err;
+  keyboxd_local_t kbl;
+
+  *r_ctx = NULL;
+  for (;;)
+    {
+      for (kbl = ctrl->keyboxd_local; kbl && kbl->is_active; kbl = kbl->next)
+        ;
+      if (kbl)
+        {
+          /* Found an inactive keyboxd session - return that.  */
+          log_assert (!kbl->is_active);
+
+          /* But first do the per session init if not yet done.  */
+          if (!kbl->per_session_init_done)
+            {
+              kbl->per_session_init_done = 1;
+            }
+
+          kbl->is_active = 1;
+
+          *r_ctx = kbl->ctx;
+          return 0;
+        }
+
+      /* None found.  Create a new session and retry.  */
+      kbl = xtrycalloc (1, sizeof *kbl);
+      if (!kbl)
+        return gpg_error_from_syserror ();
+      err = create_new_context (ctrl, &kbl->ctx);
+      if (err)
+        {
+          xfree (kbl);
+          return err;
+        }
+
+      /* Although we are not yet using nPth in gpg we better prepare
+       * to be nPth thread safe.  Thus we add it to the list and
+       * retry; this is easier than to employ a lock.  */
+      kbl->next = ctrl->keyboxd_local;
+      ctrl->keyboxd_local = kbl;
+    }
+}
+
+
+/* Close the assuan context CTX and return it to a pool of unused
+ * contexts.  If CTX is NULL, the function does nothing.  */
+static void
+close_context (ctrl_t ctrl, assuan_context_t ctx)
+{
+  keyboxd_local_t kbl;
+
+  if (!ctx)
+    return;
+
+  for (kbl = ctrl->keyboxd_local; kbl; kbl = kbl->next)
+    {
+      if (kbl->ctx == ctx)
+        {
+          if (!kbl->is_active)
+            log_fatal ("closing inactive keyboxd context %p\n", ctx);
+          kbl->is_active = 0;
+          return;
+        }
+    }
+  log_fatal ("closing unknown keyboxd ctx %p\n", ctx);
+}
+
+
+\f
+/* Create a new database handle.  A database handle is similar to a
+ * file handle: it contains a local file position.  This is used when
+ * searching: subsequent searches resume where the previous search
+ * left off.  To rewind the position, use keydb_search_reset().  This
+ * function returns NULL on error, sets ERRNO, and prints an error
+ * diagnostic.  Depending on --use-keyboxd either the old internal
+ * keydb code is used (keydb.c) or, if set, the processing is diverted
+ * to the keyboxd. */
+/* FIXME: We should change the interface to return a gpg_error_t.  */
+KEYDB_HANDLE
+keydb_new (ctrl_t ctrl)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE hd;
+
+  if (DBG_CLOCK)
+    log_clock ("keydb_new");
+
+  hd = xtrycalloc (1, sizeof *hd);
+  if (!hd)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  if (!opt.use_keyboxd)
+    {
+      err = internal_keydb_init (hd);
+      goto leave;
+    }
+  hd->use_keyboxd = 1;
+  hd->ctrl = ctrl;
+  hd->need_search_reset = 1;
+
+  err = open_context (ctrl, &hd->assuan_context);
+  if (err)
+    goto leave;
+
+ leave:
+  if (err)
+    {
+      int rc;
+      log_error (_("error opening key DB: %s\n"), gpg_strerror (err));
+      xfree (hd);
+      hd = NULL;
+      if (!(rc = gpg_err_code_to_errno (err)))
+        rc = gpg_err_code_to_errno (GPG_ERR_EIO);
+      gpg_err_set_errno (rc);
+    }
+  return hd;
+}
+
+
+/* Release a keydb handle.  */
+void
+keydb_release (KEYDB_HANDLE hd)
+{
+  if (!hd)
+    return;
+
+  if (!hd->use_keyboxd)
+    internal_keydb_deinit (hd);
+  else
+    {
+      close_context (hd->ctrl, hd->assuan_context);
+    }
+  xfree (hd);
+}
+
+
+/* Take a lock if we are not using the keyboxd.  */
+gpg_error_t
+keydb_lock (KEYDB_HANDLE hd)
+{
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (!hd->use_keyboxd)
+    return internal_keydb_lock (hd);
+
+  return 0;
+}
+
+
+\f
+/* FIXME: This helper is duplicates code of partse_keyblock_image.  */
+static gpg_error_t
+keydb_get_keyblock_do_parse (iobuf_t iobuf, int pk_no, int uid_no,
+                             kbnode_t *r_keyblock)
+{
+  gpg_error_t err;
+  struct parse_packet_ctx_s parsectx;
+  PACKET *pkt;
+  kbnode_t keyblock = NULL;
+  kbnode_t node, *tail;
+  int in_cert, save_mode;
+  int pk_count, uid_count;
+
+  *r_keyblock = NULL;
+
+  pkt = xtrymalloc (sizeof *pkt);
+  if (!pkt)
+    return gpg_error_from_syserror ();
+  init_packet (pkt);
+  init_parse_packet (&parsectx, iobuf);
+  save_mode = set_packet_list_mode (0);
+  in_cert = 0;
+  tail = NULL;
+  pk_count = uid_count = 0;
+  while ((err = parse_packet (&parsectx, pkt)) != -1)
+    {
+      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
+        {
+          free_packet (pkt, &parsectx);
+          init_packet (pkt);
+          continue;
+       }
+      if (err)
+        {
+          es_fflush (es_stdout);
+          log_error ("parse_keyblock_image: read error: %s\n",
+                     gpg_strerror (err));
+          if (gpg_err_code (err) == GPG_ERR_INV_PACKET)
+            {
+              free_packet (pkt, &parsectx);
+              init_packet (pkt);
+              continue;
+            }
+          err = gpg_error (GPG_ERR_INV_KEYRING);
+          break;
+        }
+
+      /* Filter allowed packets.  */
+      switch (pkt->pkttype)
+        {
+        case PKT_PUBLIC_KEY:
+        case PKT_PUBLIC_SUBKEY:
+        case PKT_SECRET_KEY:
+        case PKT_SECRET_SUBKEY:
+        case PKT_USER_ID:
+        case PKT_ATTRIBUTE:
+        case PKT_SIGNATURE:
+        case PKT_RING_TRUST:
+          break; /* Allowed per RFC.  */
+
+        default:
+          log_info ("skipped packet of type %d in keybox\n", (int)pkt->pkttype);
+          free_packet(pkt, &parsectx);
+          init_packet(pkt);
+          continue;
+        }
+
+      /* Other sanity checks.  */
+      if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY)
+        {
+          log_error ("parse_keyblock_image: first packet in a keybox blob "
+                     "is not a public key packet\n");
+          err = gpg_error (GPG_ERR_INV_KEYRING);
+          break;
+        }
+      if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
+                      || pkt->pkttype == PKT_SECRET_KEY))
+        {
+          log_error ("parse_keyblock_image: "
+                     "multiple keyblocks in a keybox blob\n");
+          err = gpg_error (GPG_ERR_INV_KEYRING);
+          break;
+        }
+      in_cert = 1;
+
+      node = new_kbnode (pkt);
+
+      switch (pkt->pkttype)
+        {
+        case PKT_PUBLIC_KEY:
+        case PKT_PUBLIC_SUBKEY:
+        case PKT_SECRET_KEY:
+        case PKT_SECRET_SUBKEY:
+          if (++pk_count == pk_no)
+            node->flag |= 1;
+          break;
+
+        case PKT_USER_ID:
+          if (++uid_count == uid_no)
+            node->flag |= 2;
+          break;
+
+        default:
+          break;
+        }
+
+      if (!keyblock)
+        keyblock = node;
+      else
+        *tail = node;
+      tail = &node->next;
+      pkt = xtrymalloc (sizeof *pkt);
+      if (!pkt)
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      init_packet (pkt);
+    }
+  set_packet_list_mode (save_mode);
+
+  if (err == -1 && keyblock)
+    err = 0; /* Got the entire keyblock.  */
+
+  if (err)
+    release_kbnode (keyblock);
+  else
+    {
+      *r_keyblock = keyblock;
+    }
+  free_packet (pkt, &parsectx);
+  deinit_parse_packet (&parsectx);
+  xfree (pkt);
+  return err;
+}
+
+
+/* Return the keyblock last found by keydb_search() in *RET_KB.
+ *
+ * On success, the function returns 0 and the caller must free *RET_KB
+ * using release_kbnode().  Otherwise, the function returns an error
+ * code.
+ *
+ * The returned keyblock has the kbnode flag bit 0 set for the node
+ * with the public key used to locate the keyblock or flag bit 1 set
+ * for the user ID node.  */
+gpg_error_t
+keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb)
+{
+  gpg_error_t err;
+  int pk_no, uid_no;
+
+  *ret_kb = NULL;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (DBG_CLOCK)
+    log_clock ("%s enter", __func__);
+
+  if (!hd->use_keyboxd)
+    {
+      err = internal_keydb_get_keyblock (hd, ret_kb);
+      goto leave;
+    }
+
+  if (!hd->search_result)
+    {
+      err = gpg_error (GPG_ERR_VALUE_NOT_FOUND);
+      goto leave;
+    }
+
+  pk_no = uid_no = 0;  /*FIXME: Get this from the keyboxd.  */
+  err = keydb_get_keyblock_do_parse (hd->search_result, pk_no, uid_no, ret_kb);
+  /* In contrast to the old code we close the iobuf here and thus this
+   * function may be called only once to get a keyblock.  */
+  iobuf_close (hd->search_result);
+  hd->search_result = NULL;
+
+
+ leave:
+  if (DBG_CLOCK)
+    log_clock ("%s leave%s", __func__, err? " (failed)":"");
+  return err;
+}
+
+
+/* Update the keyblock KB (i.e., extract the fingerprint and find the
+ * corresponding keyblock in the keyring).
+ *
+ * This doesn't do anything if --dry-run was specified.
+ *
+ * Returns 0 on success.  Otherwise, it returns an error code.  Note:
+ * if there isn't a keyblock in the keyring corresponding to KB, then
+ * this function returns GPG_ERR_VALUE_NOT_FOUND.
+ *
+ * This function selects the matching record and modifies the current
+ * file position to point to the record just after the selected entry.
+ * Thus, if you do a subsequent search using HD, you should first do a
+ * keydb_search_reset.  Further, if the selected record is important,
+ * you should use keydb_push_found_state and keydb_pop_found_state to
+ * save and restore it.  */
+gpg_error_t
+keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
+{
+  gpg_error_t err;
+
+  log_assert (kb);
+  log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (!hd->use_keyboxd)
+    {
+      err = internal_keydb_update_keyblock (ctrl, hd, kb);
+      goto leave;
+    }
+
+  err = GPG_ERR_NOT_IMPLEMENTED;
+
+ leave:
+  return err;
+}
+
+
+/* Insert a keyblock into one of the underlying keyrings or keyboxes.
+ *
+ * Be default, the keyring / keybox from which the last search result
+ * came is used.  If there was no previous search result (or
+ * keydb_search_reset was called), then the keyring / keybox where the
+ * next search would start is used (i.e., the current file position).
+ *
+ * Note: this doesn't do anything if --dry-run was specified.
+ *
+ * Returns 0 on success.  Otherwise, it returns an error code.  */
+gpg_error_t
+keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
+{
+  gpg_error_t err;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (!hd->use_keyboxd)
+    {
+      err = internal_keydb_insert_keyblock (hd, kb);
+      goto leave;
+    }
+
+  err = GPG_ERR_NOT_IMPLEMENTED;
+
+ leave:
+  return err;
+}
+
+
+/* Delete the currently selected keyblock.  If you haven't done a
+ * search yet on this database handle (or called keydb_search_reset),
+ * then this function returns an error.
+ *
+ * Returns 0 on success or an error code, if an error occured.  */
+gpg_error_t
+keydb_delete_keyblock (KEYDB_HANDLE hd)
+{
+  gpg_error_t err;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (!hd->use_keyboxd)
+    {
+      err = internal_keydb_delete_keyblock (hd);
+      goto leave;
+    }
+
+  err = GPG_ERR_NOT_IMPLEMENTED;
+
+ leave:
+  return err;
+}
+
+
+/* Clears the current search result and resets the handle's position
+ * so that the next search starts at the beginning of the database.
+ *
+ * Returns 0 on success and an error code if an error occurred.  */
+gpg_error_t
+keydb_search_reset (KEYDB_HANDLE hd)
+{
+  gpg_error_t err;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (DBG_CLOCK)
+    log_clock ("%s", __func__);
+  if (DBG_CACHE)
+    log_debug ("%s (hd=%p)", __func__, hd);
+
+  if (!hd->use_keyboxd)
+    {
+      err = internal_keydb_search_reset (hd);
+      goto leave;
+    }
+
+  /* All we need todo is to tell search that a reset is pending.  Noet
+   * that keydb_new sets this flag as well.  */
+  hd->need_search_reset = 1;
+  err = 0;
+
+ leave:
+  return err;
+}
+
+
+/* Search the database for keys matching the search description.  If
+ * the DB contains any legacy keys, these are silently ignored.
+ *
+ * DESC is an array of search terms with NDESC entries.  The search
+ * terms are or'd together.  That is, the next entry in the DB that
+ * matches any of the descriptions will be returned.
+ *
+ * Note: this function resumes searching where the last search left
+ * off (i.e., at the current file position).  If you want to search
+ * from the start of the database, then you need to first call
+ * keydb_search_reset().
+ *
+ * If no key matches the search description, returns
+ * GPG_ERR_NOT_FOUND.  If there was a match, returns 0.  If an error
+ * occurred, returns an error code.
+ *
+ * The returned key is considered to be selected and the raw data can,
+ * for instance, be returned by calling keydb_get_keyblock().  */
+gpg_error_t
+keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+              size_t ndesc, size_t *descindex)
+{
+  gpg_error_t err;
+  int i;
+  char line[ASSUAN_LINELENGTH];
+
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (descindex)
+    *descindex = 0; /* Make sure it is always set on return.  */
+
+  if (DBG_CLOCK)
+    log_clock ("%s enter", __func__);
+
+  if (DBG_LOOKUP)
+    {
+      log_debug ("%s: %zd search descriptions:\n", __func__, ndesc);
+      for (i = 0; i < ndesc; i ++)
+        {
+          char *t = keydb_search_desc_dump (&desc[i]);
+          log_debug ("%s   %d: %s\n", __func__, i, t);
+          xfree (t);
+        }
+    }
+
+  if (!hd->use_keyboxd)
+    {
+      err = internal_keydb_search (hd, desc, ndesc, descindex);
+      goto leave;
+    }
+
+
+  if (hd->search_result)
+    {
+      iobuf_close (hd->search_result);
+      hd->search_result = NULL;
+    }
+
+  if (!hd->need_search_reset)
+    {
+      /* No reset requested thus continue the search.  The keyboxd
+       * keeps the context of the search and thus the NEXT operates on
+       * the last search pattern.  This is how we always used the
+       * keydb.c functions.  In theory we were able to modify the
+       * search pattern between searches but that is not anymore
+       * supported by keyboxd and a cursory check does not show that
+       * we actually made used of that misfeature.  */
+      snprintf (line, sizeof line, "NEXT");
+      goto do_search;
+    }
+
+  hd->need_search_reset = 0;
+
+  if (!ndesc)
+    {
+      err = gpg_error (GPG_ERR_INV_ARG);
+      goto leave;
+    }
+
+  /* FIXME: Implement --multi */
+  switch (desc->mode)
+    {
+    case KEYDB_SEARCH_MODE_EXACT:
+      snprintf (line, sizeof line, "SEARCH =%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_SUBSTR:
+      snprintf (line, sizeof line, "SEARCH *%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_MAIL:
+      snprintf (line, sizeof line, "SEARCH <%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_MAILSUB:
+      snprintf (line, sizeof line, "SEARCH @%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_MAILEND:
+      snprintf (line, sizeof line, "SEARCH .%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_WORDS:
+      snprintf (line, sizeof line, "SEARCH +%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_SHORT_KID:
+      snprintf (line, sizeof line, "SEARCH 0x%08lX",
+                (ulong)desc->u.kid[1]);
+      break;
+
+    case KEYDB_SEARCH_MODE_LONG_KID:
+      snprintf (line, sizeof line, "SEARCH 0x%08lX%08lX",
+                (ulong)desc->u.kid[0], (ulong)desc->u.kid[1]);
+      break;
+
+    case KEYDB_SEARCH_MODE_FPR:
+      {
+        unsigned char hexfpr[MAX_FINGERPRINT_LEN * 2 + 1];
+        log_assert (desc[0].fprlen <= MAX_FINGERPRINT_LEN);
+        bin2hex (desc[0].u.fpr, desc[0].fprlen, hexfpr);
+        snprintf (line, sizeof line, "SEARCH 0x%s", hexfpr);
+      }
+      break;
+
+    case KEYDB_SEARCH_MODE_ISSUER:
+      snprintf (line, sizeof line, "SEARCH #/%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_ISSUER_SN:
+    case KEYDB_SEARCH_MODE_SN:
+      snprintf (line, sizeof line, "SEARCH #%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_SUBJECT:
+      snprintf (line, sizeof line, "SEARCH /%s", desc[0].u.name);
+      break;
+
+    case KEYDB_SEARCH_MODE_KEYGRIP:
+      {
+        unsigned char hexgrip[KEYGRIP_LEN * 2 + 1];
+        bin2hex (desc[0].u.grip, KEYGRIP_LEN, hexgrip);
+        snprintf (line, sizeof line, "SEARCH &%s", hexgrip);
+      }
+      break;
+
+    case KEYDB_SEARCH_MODE_FIRST:
+      snprintf (line, sizeof line, "SEARCH");
+      break;
+
+    case KEYDB_SEARCH_MODE_NEXT:
+      log_debug ("%s: mode next - we should not get to here!\n", __func__);
+      snprintf (line, sizeof line, "NEXT");
+      break;
+
+    default:
+      err = gpg_error (GPG_ERR_INV_ARG);
+      goto leave;
+    }
+
+ do_search:
+  {
+    membuf_t data;
+    void *buffer;
+    size_t len;
+
+    init_membuf (&data, 8192);
+    err = assuan_transact (hd->assuan_context, line,
+                           put_membuf_cb, &data,
+                           NULL, NULL,
+                           NULL, NULL);
+    if (err)
+      {
+        xfree (get_membuf (&data, &len));
+        goto leave;
+      }
+
+    buffer = get_membuf (&data, &len);
+    if (!buffer)
+      {
+        err = gpg_error_from_syserror ();
+        goto leave;
+      }
+
+    /* Fixme: Avoid double allocation.  */
+    hd->search_result = iobuf_temp_with_content (buffer, len);
+  }
+
+
+ leave:
+  if (DBG_CLOCK)
+    log_clock ("%s leave (%sfound)", __func__, err? "not ":"");
+  return err;
+}
index b5ab474..8a7144a 100644 (file)
@@ -65,7 +65,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
 
   *r_sec_avail = 0;
 
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
   if (!hd)
     return gpg_error_from_syserror ();
 
@@ -131,7 +131,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
 
   if (!secret && !force)
     {
-      if (have_secret_key_with_kid (keyid))
+      if (have_secret_key_with_kid (ctrl, keyid))
         {
           *r_sec_avail = 1;
           err = gpg_error (GPG_ERR_EOF);
@@ -141,7 +141,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
         err = 0;
     }
 
-  if (secret && !have_secret_key_with_kid (keyid))
+  if (secret && !have_secret_key_with_kid (ctrl, keyid))
     {
       err = gpg_error (GPG_ERR_NOT_FOUND);
       log_error (_("key \"%s\" not found\n"), username);
index e8bf14c..15861cc 100644 (file)
@@ -1877,7 +1877,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
     stats = &dummystats;
   *any = 0;
   init_packet (&pkt);
-  kdbhd = keydb_new ();
+  kdbhd = keydb_new (ctrl);
   if (!kdbhd)
     return gpg_error_from_syserror ();
 
index 57617a0..2cc56cd 100644 (file)
@@ -403,7 +403,7 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
       }
     else
       {
-        ctx.kr_handle = keydb_new ();
+        ctx.kr_handle = keydb_new (ctrl);
         if (!ctx.kr_handle)
           {
             rc = gpg_error_from_syserror ();
@@ -448,7 +448,7 @@ leave:
  * Return the public key in *PK.  The resources in *PK should be
  * released using release_public_key_parts().  */
 int
-get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
+get_pubkey_fast (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
 {
   int rc = 0;
   KEYDB_HANDLE hd;
@@ -476,7 +476,7 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
   }
 #endif
 
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
   if (!hd)
     return gpg_error_from_syserror ();
   rc = keydb_search_kid (hd, keyid);
@@ -550,7 +550,7 @@ get_pubkeyblock (ctrl_t ctrl, u32 * keyid)
   memset (&ctx, 0, sizeof ctx);
   /* No need to set exact here because we want the entire block.  */
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new ();
+  ctx.kr_handle = keydb_new (ctrl);
   if (!ctx.kr_handle)
     return NULL;
   ctx.nitems = 1;
@@ -592,7 +592,7 @@ get_seckey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid)
   memset (&ctx, 0, sizeof ctx);
   ctx.exact = 1; /* Use the key ID exactly as given.  */
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new ();
+  ctx.kr_handle = keydb_new (ctrl);
   if (!ctx.kr_handle)
     return gpg_error_from_syserror ();
   ctx.nitems = 1;
@@ -793,7 +793,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
     }
 
   ctx->want_secret = want_secret;
-  ctx->kr_handle = keydb_new ();
+  ctx->kr_handle = keydb_new (ctrl);
   if (!ctx->kr_handle)
     {
       rc = gpg_error_from_syserror ();
@@ -1428,7 +1428,7 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
                 err = gpg_error_from_syserror ();
               else
                 {
-                  ctx->kr_handle = keydb_new ();
+                  ctx->kr_handle = keydb_new (ctrl);
                   if (! ctx->kr_handle)
                     {
                       err = gpg_error_from_syserror ();
@@ -1574,7 +1574,7 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
       ctx.not_allocated = 1;
       /* FIXME: We should get the handle from the cache like we do in
        * get_pubkey.  */
-      ctx.kr_handle = keydb_new ();
+      ctx.kr_handle = keydb_new (ctrl);
       if (!ctx.kr_handle)
         return gpg_error_from_syserror ();
 
@@ -1612,13 +1612,14 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
  * Like get_pubkey_byfprint, PK may be NULL.  In that case, this
  * function effectively just checks for the existence of the key.  */
 gpg_error_t
-get_pubkey_byfprint_fast (PKT_public_key * pk,
+get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key * pk,
                          const byte * fprint, size_t fprint_len)
 {
   gpg_error_t err;
   KBNODE keyblock;
 
-  err = get_keyblock_byfprint_fast (&keyblock, NULL, fprint, fprint_len, 0);
+  err = get_keyblock_byfprint_fast (ctrl,
+                                    &keyblock, NULL, fprint, fprint_len, 0);
   if (!err)
     {
       if (pk)
@@ -1638,7 +1639,8 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
  * it may have a value of NULL, though.  This allows to do an insert
  * operation on a locked keydb handle.  */
 gpg_error_t
-get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
+get_keyblock_byfprint_fast (ctrl_t ctrl,
+                            kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
                             const byte *fprint, size_t fprint_len, int lock)
 {
   gpg_error_t err;
@@ -1655,7 +1657,7 @@ get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
   for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++)
     fprbuf[i] = fprint[i];
 
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
   if (!hd)
     return gpg_error_from_syserror ();
 
@@ -1737,7 +1739,7 @@ parse_def_secret_key (ctrl_t ctrl)
 
       if (! hd)
         {
-          hd = keydb_new ();
+          hd = keydb_new (ctrl);
           if (!hd)
             return NULL;
         }
@@ -2712,7 +2714,7 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
                   * reason to check that an ultimately trusted key is
                   * still valid - if it has been revoked the user
                   * should also remove the ultimate trust flag.  */
-                 if (get_pubkey_fast (ultimate_pk, sig->keyid) == 0
+                 if (get_pubkey_fast (ctrl, ultimate_pk, sig->keyid) == 0
                      && check_key_signature2 (ctrl,
                                                keyblock, k, ultimate_pk,
                                               NULL, NULL, NULL, NULL) == 0
@@ -4078,7 +4080,7 @@ key_origin_string (int origin)
    the secret key is valid; this check merely indicates whether there
    is some secret key with the specified key id.  */
 int
-have_secret_key_with_kid (u32 *keyid)
+have_secret_key_with_kid (ctrl_t ctrl, u32 *keyid)
 {
   gpg_error_t err;
   KEYDB_HANDLE kdbhd;
@@ -4087,7 +4089,7 @@ have_secret_key_with_kid (u32 *keyid)
   kbnode_t node;
   int result = 0;
 
-  kdbhd = keydb_new ();
+  kdbhd = keydb_new (ctrl);
   if (!kdbhd)
     return 0;
   memset (&desc, 0, sizeof desc);
index 0bbe723..145796c 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -361,6 +361,7 @@ enum cmd_and_opt_values
     oUseAgent,
     oNoUseAgent,
     oGpgAgentInfo,
+    oUseKeyboxd,
     oMergeOnly,
     oTryAllSecrets,
     oTrustedKey,
@@ -378,6 +379,7 @@ enum cmd_and_opt_values
     oPersonalDigestPreferences,
     oPersonalCompressPreferences,
     oAgentProgram,
+    oKeyboxdProgram,
     oDirmngrProgram,
     oDisableDirmngr,
     oDisplay,
@@ -849,6 +851,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
 
   ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
+  ARGPARSE_s_s (oKeyboxdProgram, "keyboxd-program", "@"),
   ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
   ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"),
   ARGPARSE_s_s (oDisplay,    "display",    "@"),
@@ -895,6 +898,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"),
   ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
   ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
+  ARGPARSE_s_n (oUseKeyboxd,    "use-keyboxd", "@"),
 
   /* Dummy options with warnings.  */
   ARGPARSE_s_n (oUseAgent,      "use-agent", "@"),
@@ -2734,6 +2738,11 @@ main (int argc, char **argv)
          case oGpgAgentInfo:
            obsolete_option (configname, configlineno, "gpg-agent-info");
             break;
+
+          case oUseKeyboxd:
+            opt.use_keyboxd = 1;
+            break;
+
           case oReaderPort:
            obsolete_scdaemon_option (configname, configlineno, "reader-port");
             break;
@@ -3491,6 +3500,7 @@ main (int argc, char **argv)
            pers_compress_list=pargs.r.ret_str;
            break;
           case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
+          case oKeyboxdProgram: opt.keyboxd_program = pargs.r.ret_str;  break;
           case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
          case oDisableDirmngr: opt.disable_dirmngr = 1;  break;
           case oWeakDigest:
@@ -4105,8 +4115,10 @@ main (int argc, char **argv)
     /* Add the keyrings, but not for some special commands.  We always
      * need to add the keyrings if we are running under SELinux, this
      * is so that the rings are added to the list of secured files.
-     * We do not add any keyring if --no-keyring has been used.  */
-    if (default_keyring >= 0
+     * We do not add any keyring if --no-keyring or --use-keyboxd has
+     * been used.  */
+    if (!opt.use_keyboxd
+        && default_keyring >= 0
         && (ALWAYS_ADD_KEYRINGS
             || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
       {
@@ -4118,9 +4130,8 @@ main (int argc, char **argv)
       }
     FREE_STRLIST(nrings);
 
+    /* In loopback mode, never ask for the password multiple times.  */
     if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
-      /* In loopback mode, never ask for the password multiple
-        times.  */
       {
        opt.passphrase_repeat = 0;
       }
@@ -5064,7 +5075,7 @@ main (int argc, char **argv)
 
          policy = parse_tofu_policy (argv[0]);
 
-         hd = keydb_new ();
+         hd = keydb_new (ctrl);
          if (! hd)
             {
               write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL));
index 28a77b6..adb919d 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
 /* Object used to keep state locally to server.c . */
 struct server_local_s;
 
+/* Object used to keep state locally to call-keyboxd.c .  */
+struct keyboxd_local_s;
+typedef struct keyboxd_local_s *keyboxd_local_t;
+
 /* Object used to keep state locally to call-dirmngr.c .  */
 struct dirmngr_local_s;
 typedef struct dirmngr_local_s *dirmngr_local_t;
 
 /* Object used to describe a keyblock node.  */
-typedef struct kbnode_struct *KBNODE;   /* Deprecated use kbnode_t. */
-typedef struct kbnode_struct *kbnode_t;
+typedef struct kbnode_struct *KBNODE;   /* Deprecated use kbnode_t. */typedef struct kbnode_struct *kbnode_t;
 
 /* The handle for keydb operations.  */
-typedef struct keydb_handle *KEYDB_HANDLE;
+typedef struct keydb_handle_s *KEYDB_HANDLE;
 
 /* TOFU database meta object.  */
 struct tofu_dbs_s;
@@ -96,6 +99,9 @@ struct server_control_s
   /* Local data for call-dirmngr.c  */
   dirmngr_local_t dirmngr_local;
 
+  /* Local data for call-keyboxd.c  */
+  keyboxd_local_t keyboxd_local;
+
   /* Local data for tofu.c  */
   struct {
     tofu_dbs_t dbs;
index 7b7e1dc..43cecb9 100644 (file)
@@ -614,7 +614,7 @@ pk_search_terms (const char *option, int argc, char *argv[], void *cookie)
   if (err)
     log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
 
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
 
   err = keydb_search (hd, &desc, 1, NULL);
   if (err)
@@ -810,7 +810,7 @@ sig_issuer (const char *option, int argc, char *argv[], void *cookie)
   if (err)
     log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
 
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
 
   err = keydb_search (hd, &desc, 1, NULL);
   if (err)
index c32dbf0..cab36e0 100644 (file)
@@ -2022,7 +2022,7 @@ import_one_real (ctrl_t ctrl,
     goto leave;
 
   /* Do we have this key already in one of our pubrings ? */
-  err = get_keyblock_byfprint_fast (&keyblock_orig, &hd,
+  err = get_keyblock_byfprint_fast (ctrl, &keyblock_orig, &hd,
                                     fpr2, fpr2len, 1/*locked*/);
   if ((err
        && gpg_err_code (err) != GPG_ERR_NO_PUBKEY
@@ -2310,13 +2310,13 @@ import_one_real (ctrl_t ctrl,
   if (mod_key)
     {
       revocation_present (ctrl, keyblock_orig);
-      if (!from_sk && have_secret_key_with_kid (keyid))
+      if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
         check_prefs (ctrl, keyblock_orig);
     }
   else if (new_key)
     {
       revocation_present (ctrl, keyblock);
-      if (!from_sk && have_secret_key_with_kid (keyid))
+      if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
         check_prefs (ctrl, keyblock);
     }
 
@@ -3372,7 +3372,7 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
     }
 
   /* Read the original keyblock. */
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
   if (!hd)
     {
       rc = gpg_error_from_syserror ();
@@ -3768,7 +3768,8 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
       else if (node->pkt->pkttype == PKT_SIGNATURE
                && !node->pkt->pkt.signature->flags.exportable
                && !(options&IMPORT_LOCAL_SIGS)
-               && !have_secret_key_with_kid (node->pkt->pkt.signature->keyid))
+               && !have_secret_key_with_kid (ctrl,
+                                             node->pkt->pkt.signature->keyid))
         {
           /* here we violate the rfc a bit by still allowing
            * to import non-exportable signature when we have the
@@ -4089,7 +4090,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
                        * itself?  */
                       gpg_error_t err;
 
-                     err = get_pubkey_byfprint_fast (NULL,
+                     err = get_pubkey_byfprint_fast (ctrl, NULL,
                                                       sig->revkey[idx].fpr,
                                                       sig->revkey[idx].fprlen);
                      if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY
@@ -4111,7 +4112,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
                                                        opt.keyserver, 0);
 
                              /* Do we have it now? */
-                             err = get_pubkey_byfprint_fast (NULL,
+                             err = get_pubkey_byfprint_fast (ctrl, NULL,
                                                     sig->revkey[idx].fpr,
                                                      sig->revkey[idx].fprlen);
                            }
diff --git a/g10/keydb-private.h b/g10/keydb-private.h
new file mode 100644 (file)
index 0000000..c5315b9
--- /dev/null
@@ -0,0 +1,176 @@
+/* keydb-private.h - Common definitions for keydb.c and call-keyboxd.c
+ * Copyright (C) 2019 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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 <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef G10_KEYDB_PRIVATE_H
+#define G10_KEYDB_PRIVATE_H
+
+#include <assuan.h>
+#include "../common/membuf.h"
+
+
+/* Ugly forward declarations.  */
+struct keyring_handle;
+typedef struct keyring_handle *KEYRING_HANDLE;
+struct keybox_handle;
+typedef struct keybox_handle *KEYBOX_HANDLE;
+
+
+/* This is for keydb.c and only used in non-keyboxd mode. */
+#define MAX_KEYDB_RESOURCES 40
+
+/* This is for keydb.c and only used in non-keyboxd mode. */
+typedef enum
+  {
+    KEYDB_RESOURCE_TYPE_NONE = 0,
+    KEYDB_RESOURCE_TYPE_KEYRING,
+    KEYDB_RESOURCE_TYPE_KEYBOX
+  } KeydbResourceType;
+
+/* This is for keydb.c and only used in non-keyboxd mode. */
+struct resource_item
+{
+  KeydbResourceType type;
+  union {
+    KEYRING_HANDLE kr;
+    KEYBOX_HANDLE kb;
+  } u;
+  void *token;
+};
+
+
+/* This is a simple cache used to return the last result of a
+ * successful fingerprint search.  This works only for keybox
+ * resources because (due to lack of a copy_keyblock function) we need
+ * to store an image of the keyblock which is fortunately instantly
+ * available for keyboxes.   Only used in non-keyboxd mode.  */
+enum keyblock_cache_states {
+  KEYBLOCK_CACHE_EMPTY,
+  KEYBLOCK_CACHE_PREPARED,
+  KEYBLOCK_CACHE_FILLED
+};
+
+struct keyblock_cache {
+  enum keyblock_cache_states state;
+  byte fpr[MAX_FINGERPRINT_LEN];
+  byte fprlen;
+  iobuf_t iobuf; /* Image of the keyblock.  */
+  int pk_no;
+  int uid_no;
+  /* Offset of the record in the keybox.  */
+  int resource;
+  off_t offset;
+};
+
+
+/* The definition of the KEYDB_HANDLE as used internally by keydb.c and
+ * the newer call-keyboxd.  */
+struct keydb_handle_s
+{
+  /* Flag set if this handles pertains to call-keyboxd.c.  */
+  int use_keyboxd;
+
+  /* BEGIN USE_KEYBOXD */
+  /* (These fields are only valid if USE_KEYBOXD is set.) */
+
+  /* A shallow pointer with the CTRL used to create this handle.  */
+  ctrl_t ctrl;
+
+  /* The context used to communicate with the keyboxd.  */
+  assuan_context_t assuan_context;
+
+  /* I/O buffer with the last search result or NULL.  */
+  iobuf_t search_result;
+
+  /* Flag indicating that a search reset is required.  */
+  unsigned int need_search_reset : 1;
+
+  /* END USE_KEYBOXD */
+
+  /* BEGIN !USE_KEYBOXD */
+  /* (The remaining fields are only valid if USE_KEYBOXD is cleared.)  */
+
+  /* When we locked all of the resources in ACTIVE (using keyring_lock
+   * / keybox_lock, as appropriate).  */
+  int locked;
+
+  /* If this flag is set a lock will only be released by
+   * keydb_release.  */
+  int keep_lock;
+
+  /* The index into ACTIVE of the resources in which the last search
+     result was found.  Initially -1.  */
+  int found;
+
+  /* Initially -1 (invalid).  This is used to save a search result and
+     later restore it as the selected result.  */
+  int saved_found;
+
+  /* The number of skipped long blobs since the last search
+     (keydb_search_reset).  */
+  unsigned long skipped_long_blobs;
+
+  /* If set, this disables the use of the keyblock cache.  */
+  int no_caching;
+
+  /* Whether the next search will be from the beginning of the
+     database (and thus consider all records).  */
+  int is_reset;
+
+  /* The "file position."  In our case, this is index of the current
+     resource in ACTIVE.  */
+  int current;
+
+  /* The number of resources in ACTIVE.  */
+  int used;
+
+  /* Cache of the last found and parsed key block (only used for
+     keyboxes, not keyrings).  */
+  struct keyblock_cache keyblock_cache;
+
+  /* Copy of ALL_RESOURCES when keydb_new is called.  */
+  struct resource_item active[MAX_KEYDB_RESOURCES];
+
+  /* END !USE_KEYBOXD */
+};
+
+
+/*-- keydb.c --*/
+
+/* These are the functions call-keyboxd diverts to if the keyboxd is
+ * not used.  */
+
+gpg_error_t internal_keydb_init (KEYDB_HANDLE hd);
+void internal_keydb_deinit (KEYDB_HANDLE hd);
+gpg_error_t internal_keydb_lock (KEYDB_HANDLE hd);
+
+gpg_error_t internal_keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
+gpg_error_t internal_keydb_update_keyblock (ctrl_t ctrl,
+                                            KEYDB_HANDLE hd, kbnode_t kb);
+gpg_error_t internal_keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
+gpg_error_t internal_keydb_delete_keyblock (KEYDB_HANDLE hd);
+gpg_error_t internal_keydb_search_reset (KEYDB_HANDLE hd);
+gpg_error_t internal_keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+                                   size_t ndesc, size_t *descindex);
+
+
+
+
+
+#endif /*G10_KEYDB_PRIVATE_H*/
index d3a2709..6ca2394 100644 (file)
 #include "keydb.h"
 #include "../common/i18n.h"
 
-static int active_handles;
+#include "keydb-private.h"  /* For struct keydb_handle_s */
 
-typedef enum
-  {
-    KEYDB_RESOURCE_TYPE_NONE = 0,
-    KEYDB_RESOURCE_TYPE_KEYRING,
-    KEYDB_RESOURCE_TYPE_KEYBOX
-  } KeydbResourceType;
-#define MAX_KEYDB_RESOURCES 40
+static int active_handles;
 
-struct resource_item
-{
-  KeydbResourceType type;
-  union {
-    KEYRING_HANDLE kr;
-    KEYBOX_HANDLE kb;
-  } u;
-  void *token;
-};
 
 static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
 static int used_resources;
@@ -67,74 +52,6 @@ static void *primary_keydb;
 /* Whether we have successfully registered any resource.  */
 static int any_registered;
 
-/* This is a simple cache used to return the last result of a
-   successful fingerprint search.  This works only for keybox resources
-   because (due to lack of a copy_keyblock function) we need to store
-   an image of the keyblock which is fortunately instantly available
-   for keyboxes.  */
-enum keyblock_cache_states {
-  KEYBLOCK_CACHE_EMPTY,
-  KEYBLOCK_CACHE_PREPARED,
-  KEYBLOCK_CACHE_FILLED
-};
-
-struct keyblock_cache {
-  enum keyblock_cache_states state;
-  byte fpr[MAX_FINGERPRINT_LEN];
-  byte fprlen;
-  iobuf_t iobuf; /* Image of the keyblock.  */
-  int pk_no;
-  int uid_no;
-  /* Offset of the record in the keybox.  */
-  int resource;
-  off_t offset;
-};
-
-
-struct keydb_handle
-{
-  /* When we locked all of the resources in ACTIVE (using keyring_lock
-     / keybox_lock, as appropriate).  */
-  int locked;
-
-  /* If this flag is set a lock will only be released by
-   * keydb_release.  */
-  int keep_lock;
-
-  /* The index into ACTIVE of the resources in which the last search
-     result was found.  Initially -1.  */
-  int found;
-
-  /* Initially -1 (invalid).  This is used to save a search result and
-     later restore it as the selected result.  */
-  int saved_found;
-
-  /* The number of skipped long blobs since the last search
-     (keydb_search_reset).  */
-  unsigned long skipped_long_blobs;
-
-  /* If set, this disables the use of the keyblock cache.  */
-  int no_caching;
-
-  /* Whether the next search will be from the beginning of the
-     database (and thus consider all records).  */
-  int is_reset;
-
-  /* The "file position."  In our case, this is index of the current
-     resource in ACTIVE.  */
-  int current;
-
-  /* The number of resources in ACTIVE.  */
-  int used;
-
-  /* Cache of the last found and parsed key block (only used for
-     keyboxes, not keyrings).  */
-  struct keyblock_cache keyblock_cache;
-
-  /* Copy of ALL_RESOURCES when keydb_new is called.  */
-  struct resource_item active[MAX_KEYDB_RESOURCES];
-};
-
 /* Looking up keys is expensive.  To hide the cost, we cache whether
    keys exist in the key database.  Then, if we know a key does not
    exist, we don't have to spend time looking it up.  This
@@ -273,7 +190,7 @@ kid_not_found_flush (void)
 
 
 static void
-keyblock_cache_clear (struct keydb_handle *hd)
+keyblock_cache_clear (struct keydb_handle_s *hd)
 {
   hd->keyblock_cache.state = KEYBLOCK_CACHE_EMPTY;
   iobuf_close (hd->keyblock_cache.iobuf);
@@ -875,26 +792,17 @@ keydb_dump_stats (void)
 }
 
 
-/* Create a new database handle.  A database handle is similar to a
-   file handle: it contains a local file position.  This is used when
-   searching: subsequent searches resume where the previous search
-   left off.  To rewind the position, use keydb_search_reset().  This
-   function returns NULL on error, sets ERRNO, and prints an error
-   diagnostic. */
-KEYDB_HANDLE
-keydb_new (void)
+/* keydb_new diverts to here in non-keyboxd mode.  HD is just the
+ * calloced structure with the handle type intialized.  */
+gpg_error_t
+internal_keydb_init (KEYDB_HANDLE hd)
 {
-  KEYDB_HANDLE hd;
+  gpg_error_t err = 0;
   int i, j;
   int die = 0;
   int reterrno;
 
-  if (DBG_CLOCK)
-    log_clock ("keydb_new");
-
-  hd = xtrycalloc (1, sizeof *hd);
-  if (!hd)
-    goto leave;
+  log_assert (!hd->use_keyboxd);
   hd->found = -1;
   hd->saved_found = -1;
   hd->is_reset = 1;
@@ -936,28 +844,21 @@ keydb_new (void)
   keydb_stats.handles++;
 
   if (die)
-    {
-      keydb_release (hd);
-      gpg_err_set_errno (reterrno);
-      hd = NULL;
-    }
+    err = gpg_error_from_errno (reterrno);
 
- leave:
-  if (!hd)
-    log_error (_("error opening key DB: %s\n"),
-               gpg_strerror (gpg_error_from_syserror()));
-
-  return hd;
+   return err;
 }
 
 
+/* Free all non-keyboxd resources owned by the database handle.
+ * keydb_release diverts to here.  */
 void
-keydb_release (KEYDB_HANDLE hd)
+internal_keydb_deinit (KEYDB_HANDLE hd)
 {
   int i;
 
-  if (!hd)
-    return;
+  log_assert (!hd->use_keyboxd);
+
   log_assert (active_handles > 0);
   active_handles--;
 
@@ -979,19 +880,17 @@ keydb_release (KEYDB_HANDLE hd)
     }
 
   keyblock_cache_clear (hd);
-  xfree (hd);
 }
 
 
 /* Take a lock on the files immediately and not only during insert or
  * update.  This lock is released with keydb_release.  */
 gpg_error_t
-keydb_lock (KEYDB_HANDLE hd)
+internal_keydb_lock (KEYDB_HANDLE hd)
 {
   gpg_error_t err;
 
-  if (!hd)
-    return gpg_error (GPG_ERR_INV_ARG);
+  log_assert (!hd->use_keyboxd);
 
   err = lock_all (hd);
   if (!err)
@@ -1007,7 +906,7 @@ keydb_lock (KEYDB_HANDLE hd)
 void
 keydb_disable_caching (KEYDB_HANDLE hd)
 {
-  if (hd)
+  if (hd && !hd->use_keyboxd)
     hd->no_caching = 1;
 }
 
@@ -1029,6 +928,9 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
   if (!hd)
     return NULL;
 
+  if (!hd->use_keyboxd)
+    return "[keyboxd]";
+
   if ( hd->found >= 0 && hd->found < hd->used)
     idx = hd->found;
   else if ( hd->current >= 0 && hd->current < hd->used)
@@ -1152,6 +1054,8 @@ unlock_all (KEYDB_HANDLE hd)
  * Note: it is only possible to save a single save state at a time.
  * In other words, the save stack only has room for a single
  * instance of the state.  */
+/* FIXME(keyboxd): This function is used only at one place - see how
+ * we can avoid it.  */
 void
 keydb_push_found_state (KEYDB_HANDLE hd)
 {
@@ -1183,6 +1087,8 @@ keydb_push_found_state (KEYDB_HANDLE hd)
 
 /* Restore the previous save state.  If the saved state is NULL or
    invalid, this is a NOP.  */
+/* FIXME(keyboxd): This function is used only at one place - see how
+ * we can avoid it.  */
 void
 keydb_pop_found_state (KEYDB_HANDLE hd)
 {
@@ -1347,6 +1253,7 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
 
 
 /* Return the keyblock last found by keydb_search() in *RET_KB.
+ * keydb_get_keyblock divert to here in the non-keyboxd mode.
  *
  * On success, the function returns 0 and the caller must free *RET_KB
  * using release_kbnode().  Otherwise, the function returns an error
@@ -1356,17 +1263,11 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
  * with the public key used to locate the keyblock or flag bit 1 set
  * for the user ID node.  */
 gpg_error_t
-keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
+internal_keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
 {
   gpg_error_t err = 0;
 
-  *ret_kb = NULL;
-
-  if (!hd)
-    return gpg_error (GPG_ERR_INV_ARG);
-
-  if (DBG_CLOCK)
-    log_clock ("keydb_get_keybock enter");
+  log_assert (!hd->use_keyboxd);
 
   if (hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED)
     {
@@ -1385,8 +1286,7 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
          if (err)
            keyblock_cache_clear (hd);
          if (DBG_CLOCK)
-           log_clock (err? "keydb_get_keyblock leave (cached, failed)"
-                      : "keydb_get_keyblock leave (cached)");
+           log_clock ("%s leave (cached mode)", __func__);
          return err;
        }
     }
@@ -1434,9 +1334,6 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
   if (!err)
     keydb_stats.get_keyblocks++;
 
-  if (DBG_CLOCK)
-    log_clock (err? "keydb_get_keyblock leave (failed)"
-               : "keydb_get_keyblock leave");
   return err;
 }
 
@@ -1485,6 +1382,7 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
 
 /* Update the keyblock KB (i.e., extract the fingerprint and find the
  * corresponding keyblock in the keyring).
+ * keydb_update_keyblock diverts to here in the non-keyboxd mode.
  *
  * This doesn't do anything if --dry-run was specified.
  *
@@ -1499,20 +1397,16 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
  * you should use keydb_push_found_state and keydb_pop_found_state to
  * save and restore it.  */
 gpg_error_t
-keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
+internal_keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
 {
   gpg_error_t err;
   PKT_public_key *pk;
   KEYDB_SEARCH_DESC desc;
   size_t len;
 
-  log_assert (kb);
-  log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (!hd->use_keyboxd);
   pk = kb->pkt->pkt.public_key;
 
-  if (!hd)
-    return gpg_error (GPG_ERR_INV_ARG);
-
   kid_not_found_flush ();
   keyblock_cache_clear (hd);
 
@@ -1575,6 +1469,7 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
 
 
 /* Insert a keyblock into one of the underlying keyrings or keyboxes.
+ * keydb_insert_keyblock diverts to here in the non-keyboxd mode.
  *
  * Be default, the keyring / keybox from which the last search result
  * came is used.  If there was no previous search result (or
@@ -1585,13 +1480,12 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
  *
  * Returns 0 on success.  Otherwise, it returns an error code.  */
 gpg_error_t
-keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
+internal_keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
 {
   gpg_error_t err;
   int idx;
 
-  if (!hd)
-    return gpg_error (GPG_ERR_INV_ARG);
+  log_assert (!hd->use_keyboxd);
 
   kid_not_found_flush ();
   keyblock_cache_clear (hd);
@@ -1650,12 +1544,11 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
  *
  * Returns 0 on success or an error code, if an error occurs.  */
 gpg_error_t
-keydb_delete_keyblock (KEYDB_HANDLE hd)
+internal_keydb_delete_keyblock (KEYDB_HANDLE hd)
 {
   gpg_error_t rc;
 
-  if (!hd)
-    return gpg_error (GPG_ERR_INV_ARG);
+  log_assert (!hd->use_keyboxd);
 
   kid_not_found_flush ();
   keyblock_cache_clear (hd);
@@ -1708,6 +1601,9 @@ keydb_locate_writable (KEYDB_HANDLE hd)
   if (!hd)
     return GPG_ERR_INV_ARG;
 
+  if (hd->use_keyboxd)
+    return 0;  /* No need for this here.  */
+
   rc = keydb_search_reset (hd); /* this does reset hd->current */
   if (rc)
     return rc;
@@ -1759,6 +1655,9 @@ keydb_rebuild_caches (ctrl_t ctrl, int noisy)
 {
   int i, rc;
 
+  if (opt.use_keyboxd)
+    return;  /* No need for this here.  */
+
   for (i=0; i < used_resources; i++)
     {
       if (!keyring_is_writable (all_resources[i].token))
@@ -1781,38 +1680,33 @@ keydb_rebuild_caches (ctrl_t ctrl, int noisy)
 }
 
 
-/* Return the number of skipped blocks (because they were to large to
+/* Return the number of skipped blocks (because they were too large to
    read from a keybox) since the last search reset.  */
 unsigned long
 keydb_get_skipped_counter (KEYDB_HANDLE hd)
 {
-  return hd ? hd->skipped_long_blobs : 0;
+  /*FIXME(keyboxd): Do we need this?  */
+  return hd && !hd->use_keyboxd? hd->skipped_long_blobs : 0;
 }
 
 
 /* Clears the current search result and resets the handle's position
  * so that the next search starts at the beginning of the database
  * (the start of the first resource).
+ * keydb_search_reset diverts to here in the non-keyboxd mode.
  *
  * Returns 0 on success and an error code if an error occurred.
  * (Currently, this function always returns 0 if HD is valid.)  */
 gpg_error_t
-keydb_search_reset (KEYDB_HANDLE hd)
+internal_keydb_search_reset (KEYDB_HANDLE hd)
 {
   gpg_error_t rc = 0;
   int i;
 
-  if (!hd)
-    return gpg_error (GPG_ERR_INV_ARG);
+  log_assert (!hd->use_keyboxd);
 
   keyblock_cache_clear (hd);
 
-  if (DBG_CLOCK)
-    log_clock ("keydb_search_reset");
-
-  if (DBG_CACHE)
-    log_debug ("keydb_search: reset  (hd=%p)", hd);
-
   hd->skipped_long_blobs = 0;
   hd->current = 0;
   hd->found = -1;
@@ -1840,6 +1734,7 @@ keydb_search_reset (KEYDB_HANDLE hd)
 
 /* Search the database for keys matching the search description.  If
  * the DB contains any legacy keys, these are silently ignored.
+ * keydb_search diverts to here in the non-keyboxd mode.
  *
  * DESC is an array of search terms with NDESC entries.  The search
  * terms are or'd together.  That is, the next entry in the DB that
@@ -1857,21 +1752,16 @@ keydb_search_reset (KEYDB_HANDLE hd)
  * The returned key is considered to be selected and the raw data can,
  * for instance, be returned by calling keydb_get_keyblock().  */
 gpg_error_t
-keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
-              size_t ndesc, size_t *descindex)
+internal_keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+                       size_t ndesc, size_t *descindex)
 {
-  int i;
   gpg_error_t rc;
   int was_reset = hd->is_reset;
   /* If an entry is already in the cache, then don't add it again.  */
   int already_in_cache = 0;
   int fprlen;
 
-  if (descindex)
-    *descindex = 0; /* Make sure it is always set on return.  */
-
-  if (!hd)
-    return gpg_error (GPG_ERR_INV_ARG);
+  log_assert (!hd->use_keyboxd);
 
   if (!any_registered)
     {
@@ -1879,26 +1769,11 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       return gpg_error (GPG_ERR_NOT_FOUND);
     }
 
-  if (DBG_CLOCK)
-    log_clock ("keydb_search enter");
-
-  if (DBG_LOOKUP)
-    {
-      log_debug ("%s: %zd search descriptions:\n", __func__, ndesc);
-      for (i = 0; i < ndesc; i ++)
-        {
-          char *t = keydb_search_desc_dump (&desc[i]);
-          log_debug ("%s   %d: %s\n", __func__, i, t);
-          xfree (t);
-        }
-    }
-
-
   if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID
       && (already_in_cache = kid_not_found_p (desc[0].u.kid)) == 1 )
     {
       if (DBG_CLOCK)
-        log_clock ("keydb_search leave (not found, cached)");
+        log_clock ("%s leave (not found, cached)", __func__);
       keydb_stats.notfound_cached++;
       return gpg_error (GPG_ERR_NOT_FOUND);
     }
@@ -1926,7 +1801,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
     {
       /* (DESCINDEX is already set).  */
       if (DBG_CLOCK)
-        log_clock ("keydb_search leave (cached)");
+        log_clock ("%s leave (cached)", __func__);
 
       hd->current = hd->keyblock_cache.resource;
       /* HD->KEYBLOCK_CACHE.OFFSET is the last byte in the record.
@@ -2016,9 +1891,6 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       && !already_in_cache)
     kid_not_found_insert (desc[0].u.kid);
 
-  if (DBG_CLOCK)
-    log_clock (rc? "keydb_search leave (not found)"
-                 : "keydb_search leave (found)");
   if (!rc)
     keydb_stats.found++;
   else
index 6ad8dce..25304ed 100644 (file)
@@ -163,6 +163,38 @@ is_in_klist (struct key_item *k, PKT_signature *sig)
 }
 
 
+/*-- call-keyboxd.c --*/
+
+/* Create a new database handle.  Returns NULL on error, sets ERRNO,
+ * and prints an error diagnostic. */
+KEYDB_HANDLE keydb_new (ctrl_t ctrl);
+
+/* Release a keydb handle.  */
+void keydb_release (KEYDB_HANDLE hd);
+
+/* Take a lock if we are not using the keyboxd.  */
+gpg_error_t keydb_lock (KEYDB_HANDLE hd);
+
+/* Return the keyblock last found by keydb_search.  */
+gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb);
+
+/* Update the keyblock KB.  */
+gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
+
+/* Insert a keyblock into one of the storage system.  */
+gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
+
+/* Delete the currently selected keyblock.  */
+gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
+
+/* Clears the current search result and resets the handle's position.  */
+gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
+
+/* Search the database for keys matching the search description.  */
+gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+                          size_t ndesc, size_t *descindex);
+
+
 
 /*-- keydb.c --*/
 
@@ -181,17 +213,6 @@ gpg_error_t keydb_add_resource (const char *url, unsigned int flags);
 /* Dump some statistics to the log.  */
 void keydb_dump_stats (void);
 
-/* Create a new database handle.  Returns NULL on error, sets ERRNO,
-   and prints an error diagnostic. */
-KEYDB_HANDLE keydb_new (void);
-
-/* Free all resources owned by the database handle.  */
-void keydb_release (KEYDB_HANDLE hd);
-
-/* Take a lock on the files immediately and not only during insert or
- * update.  This lock is released with keydb_release.  */
-gpg_error_t keydb_lock (KEYDB_HANDLE hd);
-
 /* Set a flag on the handle to suppress use of cached results.  This
    is required for updating a keyring and for key listings.  Fixme:
    Using a new parameter for keydb_new might be a better solution.  */
@@ -206,18 +227,6 @@ void keydb_pop_found_state (KEYDB_HANDLE hd);
 /* Return the file name of the resource.  */
 const char *keydb_get_resource_name (KEYDB_HANDLE hd);
 
-/* Return the keyblock last found by keydb_search.  */
-gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
-
-/* Update the keyblock KB.  */
-gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
-
-/* Insert a keyblock into one of the underlying keyrings or keyboxes.  */
-gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
-
-/* Delete the currently selected keyblock.  */
-gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
-
 /* Find the first writable resource.  */
 gpg_error_t keydb_locate_writable (KEYDB_HANDLE hd);
 
@@ -228,13 +237,6 @@ void keydb_rebuild_caches (ctrl_t ctrl, int noisy);
    read from a keybox) since the last search reset.  */
 unsigned long keydb_get_skipped_counter (KEYDB_HANDLE hd);
 
-/* Clears the current search result and resets the handle's position.  */
-gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
-
-/* Search the database for keys matching the search description.  */
-gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
-                          size_t ndesc, size_t *descindex);
-
 /* Return the first non-legacy key in the database.  */
 gpg_error_t keydb_search_first (KEYDB_HANDLE hd);
 
@@ -323,7 +325,7 @@ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
 /* Similar to get_pubkey, but it does not take PK->REQ_USAGE into
    account nor does it merge in the self-signed data.  This function
    also only considers primary keys.  */
-int get_pubkey_fast (PKT_public_key *pk, u32 *keyid);
+int get_pubkey_fast (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
 
 /* Return the entire keyblock used to create SIG.  This is a
  * specialized version of get_pubkeyblock.  */
@@ -383,13 +385,14 @@ int get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
 /* This function is similar to get_pubkey_byfprint, but it doesn't
    merge the self-signed data into the public key and subkeys or into
    the user ids.  */
-gpg_error_t get_pubkey_byfprint_fast (PKT_public_key *pk,
+gpg_error_t get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key *pk,
                                       const byte *fprint, size_t fprint_len);
 
 /* This function is similar to get_pubkey_byfprint, but it doesn't
    merge the self-signed data into the public key and subkeys or into
    the user ids.  */
-gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
+gpg_error_t get_keyblock_byfprint_fast (ctrl_t ctrl,
+                                        kbnode_t *r_keyblock,
                                         KEYDB_HANDLE *r_hd,
                                         const byte *fprint, size_t fprint_len,
                                         int lock);
@@ -397,7 +400,7 @@ gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
 
 /* Returns true if a secret key is available for the public key with
    key id KEYID.  */
-int have_secret_key_with_kid (u32 *keyid);
+int have_secret_key_with_kid (ctrl_t ctrl, u32 *keyid);
 
 /* Parse the --default-key parameter.  Returns the last key (in terms
    of when the option is given) that is available.  */
index 1bf5de9..9238d5d 100644 (file)
@@ -2289,7 +2289,7 @@ quick_find_keyblock (ctrl_t ctrl, const char *username,
   *r_keyblock = NULL;
 
   /* Search the key; we don't want the whole getkey stuff here.  */
-  kdbhd = keydb_new ();
+  kdbhd = keydb_new (ctrl);
   if (!kdbhd)
     {
       /* Note that keydb_new has already used log_error.  */
@@ -5761,7 +5761,7 @@ menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
        }
       else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
               && ((sig = node->pkt->pkt.signature),
-                  have_secret_key_with_kid (sig->keyid)))
+                  have_secret_key_with_kid (ctrl, sig->keyid)))
        {
          if ((sig->sig_class & ~3) == 0x10)
            {
@@ -5800,7 +5800,7 @@ menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
        }
       else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
               && ((sig = node->pkt->pkt.signature),
-                  have_secret_key_with_kid (sig->keyid)))
+                  have_secret_key_with_kid (ctrl, sig->keyid)))
        {
          if ((sig->sig_class & ~3) == 0x10)
            {
index d9037d2..5aeda36 100644 (file)
@@ -4332,7 +4332,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
     desc.mode = KEYDB_SEARCH_MODE_EXACT;
     desc.u.name = uid;
 
-    kdbhd = keydb_new ();
+    kdbhd = keydb_new (ctrl);
     if (!kdbhd)
       goto leave;
 
@@ -5184,7 +5184,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
     {
       KEYDB_HANDLE pub_hd;
 
-      pub_hd = keydb_new ();
+      pub_hd = keydb_new (ctrl);
       if (!pub_hd)
         err = gpg_error_from_syserror ();
       else
index 1274775..5f5fe9d 100644 (file)
@@ -527,7 +527,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
   if (opt.check_sigs)
     listctx.check_sigs = 1;
 
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
   if (!hd)
     rc = gpg_error_from_syserror ();
   else
index b07afb1..030bc92 100644 (file)
@@ -1196,7 +1196,7 @@ keyidlist (ctrl_t ctrl, strlist_t users, KEYDB_SEARCH_DESC **klist,
 
   *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
 
-  kdbhd = keydb_new ();
+  kdbhd = keydb_new (ctrl);
   if (!kdbhd)
     {
       rc = gpg_error_from_syserror ();
index f45b039..981315a 100644 (file)
@@ -157,7 +157,7 @@ struct expando_args
   const byte *namehash;
 };
 
-char *pct_expando(const char *string,struct expando_args *args);
+char *pct_expando (ctrl_t ctrl, const char *string,struct expando_args *args);
 void deprecated_warning(const char *configname,unsigned int configlineno,
                        const char *option,const char *repl1,const char *repl2);
 void deprecated_command (const char *name);
index 0541d2b..c2d5bbb 100644 (file)
@@ -895,7 +895,7 @@ get_signature_count (PKT_public_key *pk)
 /* Expand %-strings.  Returns a string which must be xfreed.  Returns
    NULL if the string cannot be expanded (too large). */
 char *
-pct_expando(const char *string,struct expando_args *args)
+pct_expando (ctrl_t ctrl, const char *string,struct expando_args *args)
 {
   const char *ch=string;
   int idx=0,maxlen=0,done=0;
@@ -1017,7 +1017,7 @@ pct_expando(const char *string,struct expando_args *args)
                        PKT_public_key *pk=
                          xmalloc_clear(sizeof(PKT_public_key));
 
-                       if (!get_pubkey_fast (pk,args->pksk->main_keyid))
+                       if (!get_pubkey_fast (ctrl, pk,args->pksk->main_keyid))
                          fingerprint_from_pk (pk, array, &len);
                        else
                          memset (array, 0, (len=MAX_FINGERPRINT_LEN));
index 234929b..bfa2cc3 100644 (file)
@@ -126,6 +126,7 @@ struct
   int completes_needed;
   int max_cert_depth;
   const char *agent_program;
+  const char *keyboxd_program;
   const char *dirmngr_program;
   int disable_dirmngr;
 
@@ -284,6 +285,8 @@ struct
   int only_sign_text_ids;
 
   int no_symkey_cache;   /* Disable the cache used for --symmetric.  */
+
+  int use_keyboxd;       /* Use the external keyboxd as storage backend.  */
 } opt;
 
 /* CTRL is used to keep some global variables we currently can't
index f9720d3..9bb4ab5 100644 (file)
@@ -338,7 +338,7 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
 #endif
 
        /* make command grow */
-       command=pct_expando(opt.photo_viewer,&args);
+       command=pct_expando (ctrl, opt.photo_viewer,&args);
        if(!command)
          goto fail;
 
index 0a93c31..0e39eca 100644 (file)
@@ -217,7 +217,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
 
     afx = new_armor_context ();
 
-    kdbhd = keydb_new ();
+    kdbhd = keydb_new (ctrl);
     if (!kdbhd)
       {
         rc = gpg_error_from_syserror ();
@@ -641,7 +641,7 @@ gen_revoke (ctrl_t ctrl, const char *uname)
     }
 
   /* Search the userid; we don't want the whole getkey stuff here.  */
-  kdbhd = keydb_new ();
+  kdbhd = keydb_new (ctrl);
   if (!kdbhd)
     {
       rc = gpg_error_from_syserror ();
index d715806..8c70b0a 100644 (file)
@@ -70,7 +70,7 @@ typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t;
  * a valid NAME=VALUE format.
  */
 static void
-mk_notation_policy_etc (PKT_signature *sig,
+mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
                        PKT_public_key *pk, PKT_public_key *pksk)
 {
   const char *string;
@@ -97,7 +97,7 @@ mk_notation_policy_etc (PKT_signature *sig,
 
       for (item = nd; item; item = item->next)
         {
-          item->altvalue = pct_expando (item->value,&args);
+          item->altvalue = pct_expando (ctrl, item->value,&args);
           if (!item->altvalue)
             log_error (_("WARNING: unable to %%-expand notation "
                          "(too large).  Using unexpanded.\n"));
@@ -122,7 +122,7 @@ mk_notation_policy_etc (PKT_signature *sig,
     {
       string = pu->d;
 
-      p = pct_expando (string, &args);
+      p = pct_expando (ctrl, string, &args);
       if (!p)
         {
           log_error(_("WARNING: unable to %%-expand policy URL "
@@ -145,7 +145,7 @@ mk_notation_policy_etc (PKT_signature *sig,
     {
       string = pu->d;
 
-      p = pct_expando (string, &args);
+      p = pct_expando (ctrl, string, &args);
       if (!p)
         {
           log_error (_("WARNING: unable to %%-expand preferred keyserver URL"
@@ -834,7 +834,7 @@ write_signature_packets (ctrl_t ctrl,
         BUG ();
 
       build_sig_subpkt_from_sig (sig, pk);
-      mk_notation_policy_etc (sig, NULL, pk);
+      mk_notation_policy_etc (ctrl, sig, NULL, pk);
       hash_sigversion_to_magic (md, sig, extrahash);
       gcry_md_final (md);
 
@@ -1660,7 +1660,7 @@ make_keysig_packet (ctrl_t ctrl,
   sig->sig_class = sigclass;
 
   build_sig_subpkt_from_sig (sig, pksk);
-  mk_notation_policy_etc (sig, pk, pksk);
+  mk_notation_policy_etc (ctrl, sig, pk, pksk);
 
   /* Crucial that the call to mksubpkt comes LAST before the calls
    * to finalize the sig as that makes it possible for the mksubpkt
index 167a9bb..90ce6e9 100644 (file)
 
 #include "keydb.h"
 
+
 static void
 do_test (int argc, char *argv[])
 {
+  ctrl_t ctrl;
   char *fname;
   int rc;
   KEYDB_HANDLE hd1;
@@ -33,6 +35,7 @@ do_test (int argc, char *argv[])
   (void) argc;
   (void) argv;
 
+  ctrl = xcalloc (1, sizeof *ctrl);
   /* t-keydb-get-keyblock.gpg contains two keys: a modern key followed
      by a legacy key.  If we get the keyblock for the modern key, we
      shouldn't get
@@ -44,7 +47,7 @@ do_test (int argc, char *argv[])
   if (rc)
     ABORT ("Failed to open keyring.");
 
-  hd1 = keydb_new ();
+  hd1 = keydb_new (ctrl);
   if (!hd1)
     ABORT ("");
 
@@ -62,4 +65,5 @@ do_test (int argc, char *argv[])
 
   keydb_release (hd1);
   release_kbnode (kb1);
+  xfree (ctrl);
 }
index 5eb8d01..4c78dac 100644 (file)
@@ -25,6 +25,7 @@ static void
 do_test (int argc, char *argv[])
 {
   int rc;
+  ctrl_t ctrl;
   KEYDB_HANDLE hd1, hd2;
   KEYDB_SEARCH_DESC desc1, desc2;
   KBNODE kb1, kb2, p;
@@ -35,16 +36,17 @@ do_test (int argc, char *argv[])
   (void) argc;
   (void) argv;
 
+  ctrl = xcalloc (1, sizeof *ctrl);
   fname = prepend_srcdir ("t-keydb-keyring.kbx");
   rc = keydb_add_resource (fname, 0);
   test_free (fname);
   if (rc)
     ABORT ("Failed to open keyring.");
 
-  hd1 = keydb_new ();
+  hd1 = keydb_new (ctrl);
   if (!hd1)
     ABORT ("");
-  hd2 = keydb_new ();
+  hd2 = keydb_new (ctrl);
   if (!hd2)
     ABORT ("");
 
@@ -101,4 +103,5 @@ do_test (int argc, char *argv[])
   release_kbnode (kb2);
   keydb_release (hd1);
   keydb_release (hd2);
+  xfree (ctrl);
 }
index e78da15..2eda1ff 100644 (file)
@@ -2131,7 +2131,7 @@ build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs,
   /* If two keys have cross signatures, then they are controlled by
    * the same person and thus are not in conflict.  */
   kb_all = xcalloc (sizeof (kb_all[0]), conflict_set_count);
-  hd = keydb_new ();
+  hd = keydb_new (ctrl);
   for (i = 0, iter = conflict_set;
        i < conflict_set_count;
        i ++, iter = iter->next)
index a230a6c..352aece 100644 (file)
@@ -2015,7 +2015,7 @@ validate_keys (ctrl_t ctrl, int interactive)
      trust. */
   keydb_rebuild_caches (ctrl, 0);
 
-  kdb = keydb_new ();
+  kdb = keydb_new (ctrl);
   if (!kdb)
     return gpg_error_from_syserror ();