diff options
author | Werner Koch <wk@gnupg.org> | 2019-09-09 14:34:09 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2019-09-09 15:01:47 +0200 |
commit | aba82684fe14289cf62b4694bc398f3a274b4762 (patch) | |
tree | b66c13bcb29f62f64c4aaa603d510b0fd65cb7cc /g10 | |
parent | kbx: Fix keyboxd search first. (diff) | |
download | gnupg2-aba82684fe14289cf62b4694bc398f3a274b4762.tar.xz gnupg2-aba82684fe14289cf62b4694bc398f3a274b4762.zip |
gpg: New option --use-keyboxd.
* 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>
Diffstat (limited to 'g10')
-rw-r--r-- | g10/Makefile.am | 32 | ||||
-rw-r--r-- | g10/call-keyboxd.c | 842 | ||||
-rw-r--r-- | g10/delkey.c | 6 | ||||
-rw-r--r-- | g10/export.c | 2 | ||||
-rw-r--r-- | g10/getkey.c | 34 | ||||
-rw-r--r-- | g10/gpg.c | 21 | ||||
-rw-r--r-- | g10/gpg.h | 12 | ||||
-rw-r--r-- | g10/gpgcompose.c | 4 | ||||
-rw-r--r-- | g10/import.c | 15 | ||||
-rw-r--r-- | g10/keydb-private.h | 176 | ||||
-rw-r--r-- | g10/keydb.c | 240 | ||||
-rw-r--r-- | g10/keydb.h | 71 | ||||
-rw-r--r-- | g10/keyedit.c | 6 | ||||
-rw-r--r-- | g10/keygen.c | 4 | ||||
-rw-r--r-- | g10/keylist.c | 2 | ||||
-rw-r--r-- | g10/keyserver.c | 2 | ||||
-rw-r--r-- | g10/main.h | 2 | ||||
-rw-r--r-- | g10/misc.c | 4 | ||||
-rw-r--r-- | g10/options.h | 3 | ||||
-rw-r--r-- | g10/photoid.c | 2 | ||||
-rw-r--r-- | g10/revoke.c | 4 | ||||
-rw-r--r-- | g10/sign.c | 12 | ||||
-rw-r--r-- | g10/t-keydb-get-keyblock.c | 6 | ||||
-rw-r--r-- | g10/t-keydb.c | 7 | ||||
-rw-r--r-- | g10/tofu.c | 2 | ||||
-rw-r--r-- | g10/trustdb.c | 2 |
26 files changed, 1221 insertions, 292 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am index 884b4749b..1404014e9 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -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 index 000000000..f05a9e85f --- /dev/null +++ b/g10/call-keyboxd.c @@ -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; +}; + + + + +/* 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); +} + + + +/* 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; +} + + + +/* 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; +} diff --git a/g10/delkey.c b/g10/delkey.c index b5ab47434..8a7144ace 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -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); diff --git a/g10/export.c b/g10/export.c index e8bf14cf5..15861cc0d 100644 --- a/g10/export.c +++ b/g10/export.c @@ -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 (); diff --git a/g10/getkey.c b/g10/getkey.c index 57617a0a9..2cc56cdbd 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -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); @@ -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)); @@ -60,16 +60,19 @@ /* 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; diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index 7b7e1dc9a..43cecb90e 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -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) diff --git a/g10/import.c b/g10/import.c index c32dbf059..cab36e0b2 100644 --- a/g10/import.c +++ b/g10/import.c @@ -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 index 000000000..c5315b991 --- /dev/null +++ b/g10/keydb-private.h @@ -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*/ diff --git a/g10/keydb.c b/g10/keydb.c index d3a2709bc..6ca239475 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -37,25 +37,10 @@ #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 diff --git a/g10/keydb.h b/g10/keydb.h index 6ad8dce4c..25304ed25 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -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. */ diff --git a/g10/keyedit.c b/g10/keyedit.c index 1bf5de9b2..9238d5d53 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -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) { diff --git a/g10/keygen.c b/g10/keygen.c index d9037d29d..5aeda36ce 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -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 diff --git a/g10/keylist.c b/g10/keylist.c index 1274775d2..5f5fe9d34 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -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 diff --git a/g10/keyserver.c b/g10/keyserver.c index b07afb128..030bc9297 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -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 (); diff --git a/g10/main.h b/g10/main.h index f45b03909..981315a4a 100644 --- a/g10/main.h +++ b/g10/main.h @@ -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); diff --git a/g10/misc.c b/g10/misc.c index 0541d2b77..c2d5bbb8e 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -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)); diff --git a/g10/options.h b/g10/options.h index 234929b15..bfa2cc31e 100644 --- a/g10/options.h +++ b/g10/options.h @@ -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 diff --git a/g10/photoid.c b/g10/photoid.c index f9720d329..9bb4ab58f 100644 --- a/g10/photoid.c +++ b/g10/photoid.c @@ -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; diff --git a/g10/revoke.c b/g10/revoke.c index 0a93c31f9..0e39eca61 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -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 (); diff --git a/g10/sign.c b/g10/sign.c index d71580639..8c70b0a2e 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -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 diff --git a/g10/t-keydb-get-keyblock.c b/g10/t-keydb-get-keyblock.c index 167a9bbee..90ce6e9a6 100644 --- a/g10/t-keydb-get-keyblock.c +++ b/g10/t-keydb-get-keyblock.c @@ -21,9 +21,11 @@ #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); } diff --git a/g10/t-keydb.c b/g10/t-keydb.c index 5eb8d0154..4c78dac48 100644 --- a/g10/t-keydb.c +++ b/g10/t-keydb.c @@ -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); } diff --git a/g10/tofu.c b/g10/tofu.c index e78da15c1..2eda1ff30 100644 --- a/g10/tofu.c +++ b/g10/tofu.c @@ -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) diff --git a/g10/trustdb.c b/g10/trustdb.c index a230a6c03..352aecede 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -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 (); |