mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
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>
This commit is contained in:
parent
5e00c1773d
commit
aba82684fe
26 changed files with 1221 additions and 292 deletions
240
g10/keydb.c
240
g10/keydb.c
|
@ -37,25 +37,10 @@
|
|||
#include "keydb.h"
|
||||
#include "../common/i18n.h"
|
||||
|
||||
#include "keydb-private.h" /* For struct keydb_handle_s */
|
||||
|
||||
static int active_handles;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KEYDB_RESOURCE_TYPE_NONE = 0,
|
||||
KEYDB_RESOURCE_TYPE_KEYRING,
|
||||
KEYDB_RESOURCE_TYPE_KEYBOX
|
||||
} KeydbResourceType;
|
||||
#define MAX_KEYDB_RESOURCES 40
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue