mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
096e7457ec
The asymmetric quotes used by GNU in the past (`...') don't render nicely on modern systems. We now use two \x27 characters ('...'). The proper solution would be to use the correct Unicode symmetric quotes here. However this has the disadvantage that the system requires Unicode support. We don't want that today. If Unicode is available a generated po file can be used to output proper quotes. A simple sed script like the one used for en@quote is sufficient to change them. The changes have been done by applying sed -i "s/\`\([^'\`]*\)'/'\1'/g" to most files and fixing obvious problems by hand. The msgid strings in the po files were fixed with a similar command.
853 lines
20 KiB
C
853 lines
20 KiB
C
/* keydb.c - key database dispatcher
|
||
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
|
||
* 2008, 2009, 2011 Free Software Foundation, Inc.
|
||
*
|
||
* 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 <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include <config.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <errno.h>
|
||
#include <assert.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <unistd.h>
|
||
|
||
#include "gpg.h"
|
||
#include "util.h"
|
||
#include "options.h"
|
||
#include "main.h" /*try_make_homedir ()*/
|
||
#include "packet.h"
|
||
#include "keyring.h"
|
||
#include "keydb.h"
|
||
#include "i18n.h"
|
||
|
||
static int active_handles;
|
||
|
||
typedef enum
|
||
{
|
||
KEYDB_RESOURCE_TYPE_NONE = 0,
|
||
KEYDB_RESOURCE_TYPE_KEYRING
|
||
} KeydbResourceType;
|
||
#define MAX_KEYDB_RESOURCES 40
|
||
|
||
struct resource_item
|
||
{
|
||
KeydbResourceType type;
|
||
union {
|
||
KEYRING_HANDLE kr;
|
||
} u;
|
||
void *token;
|
||
};
|
||
|
||
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
||
static int used_resources;
|
||
static void *primary_keyring=NULL;
|
||
|
||
struct keydb_handle
|
||
{
|
||
int locked;
|
||
int found;
|
||
int current;
|
||
int used; /* Number of items in ACTIVE. */
|
||
struct resource_item active[MAX_KEYDB_RESOURCES];
|
||
};
|
||
|
||
|
||
static int lock_all (KEYDB_HANDLE hd);
|
||
static void unlock_all (KEYDB_HANDLE hd);
|
||
|
||
|
||
/* Handle the creation of a keyring if it does not yet exist. Take
|
||
into acount that other processes might have the keyring already
|
||
locked. This lock check does not work if the directory itself is
|
||
not yet available. */
|
||
static int
|
||
maybe_create_keyring (char *filename, int force)
|
||
{
|
||
dotlock_t lockhd = NULL;
|
||
IOBUF iobuf;
|
||
int rc;
|
||
mode_t oldmask;
|
||
char *last_slash_in_filename;
|
||
int save_slash;
|
||
|
||
/* A quick test whether the filename already exists. */
|
||
if (!access (filename, F_OK))
|
||
return 0;
|
||
|
||
/* If we don't want to create a new file at all, there is no need to
|
||
go any further - bail out right here. */
|
||
if (!force)
|
||
return gpg_error (GPG_ERR_ENOENT);
|
||
|
||
/* First of all we try to create the home directory. Note, that we
|
||
don't do any locking here because any sane application of gpg
|
||
would create the home directory by itself and not rely on gpg's
|
||
tricky auto-creation which is anyway only done for some home
|
||
directory name patterns. */
|
||
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
||
#if HAVE_W32_SYSTEM
|
||
{
|
||
/* Windows may either have a slash or a backslash. Take care of it. */
|
||
char *p = strrchr (filename, '/');
|
||
if (!last_slash_in_filename || p > last_slash_in_filename)
|
||
last_slash_in_filename = p;
|
||
}
|
||
#endif /*HAVE_W32_SYSTEM*/
|
||
if (!last_slash_in_filename)
|
||
return gpg_error (GPG_ERR_ENOENT); /* No slash at all - should
|
||
not happen though. */
|
||
save_slash = *last_slash_in_filename;
|
||
*last_slash_in_filename = 0;
|
||
if (access(filename, F_OK))
|
||
{
|
||
static int tried;
|
||
|
||
if (!tried)
|
||
{
|
||
tried = 1;
|
||
try_make_homedir (filename);
|
||
}
|
||
if (access (filename, F_OK))
|
||
{
|
||
rc = gpg_error_from_syserror ();
|
||
*last_slash_in_filename = save_slash;
|
||
goto leave;
|
||
}
|
||
}
|
||
*last_slash_in_filename = save_slash;
|
||
|
||
/* To avoid races with other instances of gpg trying to create or
|
||
update the keyring (it is removed during an update for a short
|
||
time), we do the next stuff in a locked state. */
|
||
lockhd = dotlock_create (filename, 0);
|
||
if (!lockhd)
|
||
{
|
||
/* A reason for this to fail is that the directory is not
|
||
writable. However, this whole locking stuff does not make
|
||
sense if this is the case. An empty non-writable directory
|
||
with no keyring is not really useful at all. */
|
||
if (opt.verbose)
|
||
log_info ("can't allocate lock for '%s'\n", filename );
|
||
|
||
if (!force)
|
||
return gpg_error (GPG_ERR_ENOENT);
|
||
else
|
||
return gpg_error (GPG_ERR_GENERAL);
|
||
}
|
||
|
||
if ( dotlock_take (lockhd, -1) )
|
||
{
|
||
/* This is something bad. Probably a stale lockfile. */
|
||
log_info ("can't lock '%s'\n", filename );
|
||
rc = G10ERR_GENERAL;
|
||
goto leave;
|
||
}
|
||
|
||
/* Now the real test while we are locked. */
|
||
if (!access(filename, F_OK))
|
||
{
|
||
rc = 0; /* Okay, we may access the file now. */
|
||
goto leave;
|
||
}
|
||
|
||
/* The file does not yet exist, create it now. */
|
||
oldmask = umask (077);
|
||
if (is_secured_filename (filename))
|
||
{
|
||
iobuf = NULL;
|
||
gpg_err_set_errno (EPERM);
|
||
}
|
||
else
|
||
iobuf = iobuf_create (filename);
|
||
umask (oldmask);
|
||
if (!iobuf)
|
||
{
|
||
rc = gpg_error_from_syserror ();
|
||
log_error ( _("error creating keyring '%s': %s\n"),
|
||
filename, strerror(errno));
|
||
goto leave;
|
||
}
|
||
|
||
if (!opt.quiet)
|
||
log_info (_("keyring '%s' created\n"), filename);
|
||
|
||
iobuf_close (iobuf);
|
||
/* Must invalidate that ugly cache */
|
||
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, filename);
|
||
rc = 0;
|
||
|
||
leave:
|
||
if (lockhd)
|
||
{
|
||
dotlock_release (lockhd);
|
||
dotlock_destroy (lockhd);
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
|
||
/*
|
||
* Register a resource (which currently may only be a keyring file).
|
||
* The first keyring which is added by this function is
|
||
* created if it does not exist.
|
||
* Note: this function may be called before secure memory is
|
||
* available.
|
||
* Flag 1 - Force.
|
||
* Flag 2 - Mark resource as primary.
|
||
* Flag 4 - This is a default resources.
|
||
* Flag 8 - Open as read-only.
|
||
*/
|
||
gpg_error_t
|
||
keydb_add_resource (const char *url, int flags)
|
||
{
|
||
static int any_public;
|
||
const char *resname = url;
|
||
char *filename = NULL;
|
||
int force = (flags&1);
|
||
int read_only = !!(flags&8);
|
||
int rc = 0;
|
||
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
||
void *token;
|
||
|
||
if (read_only)
|
||
force = 0;
|
||
|
||
/* Do we have an URL?
|
||
* gnupg-ring:filename := this is a plain keyring
|
||
* filename := See what is is, but create as plain keyring.
|
||
*/
|
||
if (strlen (resname) > 11)
|
||
{
|
||
if (!strncmp( resname, "gnupg-ring:", 11) )
|
||
{
|
||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||
resname += 11;
|
||
}
|
||
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
|
||
else if (strchr (resname, ':'))
|
||
{
|
||
log_error ("invalid key resource URL '%s'\n", url );
|
||
rc = gpg_error (GPG_ERR_GENERAL);
|
||
goto leave;
|
||
}
|
||
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
|
||
}
|
||
|
||
if (*resname != DIRSEP_C )
|
||
{
|
||
/* Do tilde expansion etc. */
|
||
if (strchr(resname, DIRSEP_C) )
|
||
filename = make_filename (resname, NULL);
|
||
else
|
||
filename = make_filename (opt.homedir, resname, NULL);
|
||
}
|
||
else
|
||
filename = xstrdup (resname);
|
||
|
||
if (!force && !read_only)
|
||
force = !any_public;
|
||
|
||
/* See whether we can determine the filetype. */
|
||
if (rt == KEYDB_RESOURCE_TYPE_NONE)
|
||
{
|
||
FILE *fp = fopen (filename, "rb");
|
||
|
||
if (fp)
|
||
{
|
||
u32 magic;
|
||
|
||
if (fread( &magic, 4, 1, fp) == 1 )
|
||
{
|
||
if (magic == 0x13579ace || magic == 0xce9a5713)
|
||
; /* GDBM magic - not anymore supported. */
|
||
else
|
||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||
}
|
||
else /* Maybe empty: assume keyring. */
|
||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||
|
||
fclose( fp );
|
||
}
|
||
else /* No file yet: create keyring. */
|
||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||
}
|
||
|
||
switch (rt)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
log_error ("unknown type of key resource '%s'\n", url );
|
||
rc = gpg_error (GPG_ERR_GENERAL);
|
||
goto leave;
|
||
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = maybe_create_keyring (filename, force);
|
||
if (rc)
|
||
goto leave;
|
||
|
||
if (keyring_register_filename (filename, read_only, &token))
|
||
{
|
||
if (used_resources >= MAX_KEYDB_RESOURCES)
|
||
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
||
else
|
||
{
|
||
if (flags&2)
|
||
primary_keyring = token;
|
||
all_resources[used_resources].type = rt;
|
||
all_resources[used_resources].u.kr = NULL; /* Not used here */
|
||
all_resources[used_resources].token = token;
|
||
used_resources++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* This keyring was already registered, so ignore it.
|
||
However, we can still mark it as primary even if it was
|
||
already registered. */
|
||
if (flags&2)
|
||
primary_keyring = token;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
log_error ("resource type of '%s' not supported\n", url);
|
||
rc = gpg_error (GPG_ERR_GENERAL);
|
||
goto leave;
|
||
}
|
||
|
||
/* fixme: check directory permissions and print a warning */
|
||
|
||
leave:
|
||
if (rc)
|
||
log_error (_("keyblock resource '%s': %s\n"), filename, gpg_strerror (rc));
|
||
else
|
||
any_public = 1;
|
||
xfree (filename);
|
||
return rc;
|
||
}
|
||
|
||
|
||
|
||
|
||
KEYDB_HANDLE
|
||
keydb_new (void)
|
||
{
|
||
KEYDB_HANDLE hd;
|
||
int i, j;
|
||
|
||
hd = xmalloc_clear (sizeof *hd);
|
||
hd->found = -1;
|
||
|
||
assert (used_resources <= MAX_KEYDB_RESOURCES);
|
||
for (i=j=0; i < used_resources; i++)
|
||
{
|
||
switch (all_resources[i].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
hd->active[j].type = all_resources[i].type;
|
||
hd->active[j].token = all_resources[i].token;
|
||
hd->active[j].u.kr = keyring_new (all_resources[i].token);
|
||
if (!hd->active[j].u.kr) {
|
||
xfree (hd);
|
||
return NULL; /* fixme: release all previously allocated handles*/
|
||
}
|
||
j++;
|
||
break;
|
||
}
|
||
}
|
||
hd->used = j;
|
||
|
||
active_handles++;
|
||
return hd;
|
||
}
|
||
|
||
void
|
||
keydb_release (KEYDB_HANDLE hd)
|
||
{
|
||
int i;
|
||
|
||
if (!hd)
|
||
return;
|
||
assert (active_handles > 0);
|
||
active_handles--;
|
||
|
||
unlock_all (hd);
|
||
for (i=0; i < hd->used; i++)
|
||
{
|
||
switch (hd->active[i].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
keyring_release (hd->active[i].u.kr);
|
||
break;
|
||
}
|
||
}
|
||
|
||
xfree (hd);
|
||
}
|
||
|
||
|
||
/*
|
||
* Return the name of the current resource. This is function first
|
||
* looks for the last found found, then for the current search
|
||
* position, and last returns the first available resource. The
|
||
* returned string is only valid as long as the handle exists. This
|
||
* function does only return NULL if no handle is specified, in all
|
||
* other error cases an empty string is returned.
|
||
*/
|
||
const char *
|
||
keydb_get_resource_name (KEYDB_HANDLE hd)
|
||
{
|
||
int idx;
|
||
const char *s = NULL;
|
||
|
||
if (!hd)
|
||
return NULL;
|
||
|
||
if ( hd->found >= 0 && hd->found < hd->used)
|
||
idx = hd->found;
|
||
else if ( hd->current >= 0 && hd->current < hd->used)
|
||
idx = hd->current;
|
||
else
|
||
idx = 0;
|
||
|
||
switch (hd->active[idx].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
s = NULL;
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
s = keyring_get_resource_name (hd->active[idx].u.kr);
|
||
break;
|
||
}
|
||
|
||
return s? s: "";
|
||
}
|
||
|
||
|
||
|
||
static int
|
||
lock_all (KEYDB_HANDLE hd)
|
||
{
|
||
int i, rc = 0;
|
||
|
||
for (i=0; !rc && i < hd->used; i++)
|
||
{
|
||
switch (hd->active[i].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = keyring_lock (hd->active[i].u.kr, 1);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (rc)
|
||
{
|
||
/* Revert the already set locks. */
|
||
for (i--; i >= 0; i--)
|
||
{
|
||
switch (hd->active[i].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
keyring_lock (hd->active[i].u.kr, 0);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
hd->locked = 1;
|
||
|
||
return rc;
|
||
}
|
||
|
||
|
||
static void
|
||
unlock_all (KEYDB_HANDLE hd)
|
||
{
|
||
int i;
|
||
|
||
if (!hd->locked)
|
||
return;
|
||
|
||
for (i=hd->used-1; i >= 0; i--)
|
||
{
|
||
switch (hd->active[i].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
keyring_lock (hd->active[i].u.kr, 0);
|
||
break;
|
||
}
|
||
}
|
||
hd->locked = 0;
|
||
}
|
||
|
||
|
||
/*
|
||
* Return the last found keyring. Caller must free it.
|
||
* The returned keyblock has the kbode 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 *ret_kb)
|
||
{
|
||
gpg_error_t err = 0;
|
||
|
||
if (!hd)
|
||
return gpg_error (GPG_ERR_INV_ARG);
|
||
|
||
if (hd->found < 0 || hd->found >= hd->used)
|
||
return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
||
|
||
switch (hd->active[hd->found].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
err = gpg_error (GPG_ERR_GENERAL); /* oops */
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
err = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
|
||
break;
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
/*
|
||
* Update the current keyblock with the keyblock KB
|
||
*/
|
||
gpg_error_t
|
||
keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
||
{
|
||
gpg_error_t rc;
|
||
|
||
if (!hd)
|
||
return gpg_error (GPG_ERR_INV_ARG);
|
||
|
||
if (hd->found < 0 || hd->found >= hd->used)
|
||
return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
||
|
||
if (opt.dry_run)
|
||
return 0;
|
||
|
||
rc = lock_all (hd);
|
||
if (rc)
|
||
return rc;
|
||
|
||
switch (hd->active[hd->found].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
rc = gpg_error (GPG_ERR_GENERAL); /* oops */
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
|
||
break;
|
||
}
|
||
|
||
unlock_all (hd);
|
||
return rc;
|
||
}
|
||
|
||
|
||
/*
|
||
* Insert a new KB into one of the resources.
|
||
*/
|
||
gpg_error_t
|
||
keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
||
{
|
||
int rc;
|
||
int idx;
|
||
|
||
if (!hd)
|
||
return gpg_error (GPG_ERR_INV_ARG);
|
||
|
||
if (opt.dry_run)
|
||
return 0;
|
||
|
||
if (hd->found >= 0 && hd->found < hd->used)
|
||
idx = hd->found;
|
||
else if (hd->current >= 0 && hd->current < hd->used)
|
||
idx = hd->current;
|
||
else
|
||
return gpg_error (GPG_ERR_GENERAL);
|
||
|
||
rc = lock_all (hd);
|
||
if (rc)
|
||
return rc;
|
||
|
||
switch (hd->active[idx].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
rc = gpg_error (GPG_ERR_GENERAL); /* oops */
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
|
||
break;
|
||
}
|
||
|
||
unlock_all (hd);
|
||
return rc;
|
||
}
|
||
|
||
|
||
/*
|
||
* Delete the current keyblock.
|
||
*/
|
||
gpg_error_t
|
||
keydb_delete_keyblock (KEYDB_HANDLE hd)
|
||
{
|
||
gpg_error_t rc;
|
||
|
||
if (!hd)
|
||
return gpg_error (GPG_ERR_INV_ARG);
|
||
|
||
if (hd->found < 0 || hd->found >= hd->used)
|
||
return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
||
|
||
if (opt.dry_run)
|
||
return 0;
|
||
|
||
rc = lock_all (hd);
|
||
if (rc)
|
||
return rc;
|
||
|
||
switch (hd->active[hd->found].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
rc = gpg_error (GPG_ERR_GENERAL);
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
|
||
break;
|
||
}
|
||
|
||
unlock_all (hd);
|
||
return rc;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Locate the default writable key resource, so that the next
|
||
* operation (which is only relevant for inserts) will be done on this
|
||
* resource.
|
||
*/
|
||
gpg_error_t
|
||
keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
|
||
{
|
||
gpg_error_t rc;
|
||
|
||
(void)reserved;
|
||
|
||
if (!hd)
|
||
return G10ERR_INV_ARG;
|
||
|
||
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
||
if (rc)
|
||
return rc;
|
||
|
||
/* If we have a primary set, try that one first */
|
||
if (primary_keyring)
|
||
{
|
||
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
||
{
|
||
if(hd->active[hd->current].token==primary_keyring)
|
||
{
|
||
if(keyring_is_writable (hd->active[hd->current].token))
|
||
return 0;
|
||
else
|
||
break;
|
||
}
|
||
}
|
||
|
||
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
||
if (rc)
|
||
return rc;
|
||
}
|
||
|
||
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
||
{
|
||
switch (hd->active[hd->current].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
BUG();
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
if (keyring_is_writable (hd->active[hd->current].token))
|
||
return 0; /* found (hd->current is set to it) */
|
||
break;
|
||
}
|
||
}
|
||
|
||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||
}
|
||
|
||
/*
|
||
* Rebuild the caches of all key resources.
|
||
*/
|
||
void
|
||
keydb_rebuild_caches (int noisy)
|
||
{
|
||
int i, rc;
|
||
|
||
for (i=0; i < used_resources; i++)
|
||
{
|
||
if (!keyring_is_writable (all_resources[i].token))
|
||
continue;
|
||
switch (all_resources[i].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = keyring_rebuild_cache (all_resources[i].token,noisy);
|
||
if (rc)
|
||
log_error (_("failed to rebuild keyring cache: %s\n"),
|
||
g10_errstr (rc));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Start the next search on this handle right at the beginning
|
||
*/
|
||
gpg_error_t
|
||
keydb_search_reset (KEYDB_HANDLE hd)
|
||
{
|
||
gpg_error_t rc = 0;
|
||
int i;
|
||
|
||
if (!hd)
|
||
return gpg_error (GPG_ERR_INV_ARG);
|
||
|
||
hd->current = 0;
|
||
hd->found = -1;
|
||
/* Now reset all resources. */
|
||
for (i=0; !rc && i < hd->used; i++)
|
||
{
|
||
switch (hd->active[i].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = keyring_search_reset (hd->active[i].u.kr);
|
||
break;
|
||
}
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
|
||
/*
|
||
* Search through all keydb resources, starting at the current
|
||
* position, for a keyblock which contains one of the keys described
|
||
* in the DESC array. Returns GPG_ERR_NOT_FOUND if no matching
|
||
* keyring was found.
|
||
*/
|
||
gpg_error_t
|
||
keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||
size_t ndesc, size_t *descindex)
|
||
{
|
||
gpg_error_t rc;
|
||
|
||
if (!hd)
|
||
return gpg_error (GPG_ERR_INV_ARG);
|
||
|
||
rc = -1;
|
||
while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
|
||
&& hd->current >= 0 && hd->current < hd->used)
|
||
{
|
||
switch (hd->active[hd->current].type)
|
||
{
|
||
case KEYDB_RESOURCE_TYPE_NONE:
|
||
BUG(); /* we should never see it here */
|
||
break;
|
||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||
rc = keyring_search (hd->active[hd->current].u.kr, desc,
|
||
ndesc, descindex);
|
||
break;
|
||
}
|
||
if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
|
||
{
|
||
/* EOF -> switch to next resource */
|
||
hd->current++;
|
||
}
|
||
else if (!rc)
|
||
hd->found = hd->current;
|
||
}
|
||
|
||
return ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
|
||
? gpg_error (GPG_ERR_NOT_FOUND)
|
||
: rc);
|
||
}
|
||
|
||
|
||
gpg_error_t
|
||
keydb_search_first (KEYDB_HANDLE hd)
|
||
{
|
||
KEYDB_SEARCH_DESC desc;
|
||
|
||
memset (&desc, 0, sizeof desc);
|
||
desc.mode = KEYDB_SEARCH_MODE_FIRST;
|
||
return keydb_search (hd, &desc, 1);
|
||
}
|
||
|
||
gpg_error_t
|
||
keydb_search_next (KEYDB_HANDLE hd)
|
||
{
|
||
KEYDB_SEARCH_DESC desc;
|
||
|
||
memset (&desc, 0, sizeof desc);
|
||
desc.mode = KEYDB_SEARCH_MODE_NEXT;
|
||
return keydb_search (hd, &desc, 1);
|
||
}
|
||
|
||
gpg_error_t
|
||
keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
|
||
{
|
||
KEYDB_SEARCH_DESC desc;
|
||
|
||
memset (&desc, 0, sizeof desc);
|
||
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
|
||
desc.u.kid[0] = kid[0];
|
||
desc.u.kid[1] = kid[1];
|
||
return keydb_search (hd, &desc, 1);
|
||
}
|
||
|
||
gpg_error_t
|
||
keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
|
||
{
|
||
KEYDB_SEARCH_DESC desc;
|
||
|
||
memset (&desc, 0, sizeof desc);
|
||
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
||
memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
|
||
return keydb_search (hd, &desc, 1);
|
||
}
|