2003-06-05 07:14:21 +00:00
|
|
|
|
/* keydb.c - key database dispatcher
|
2011-02-04 12:57:53 +01:00
|
|
|
|
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
|
2013-01-07 21:14:52 +01:00
|
|
|
|
* 2008, 2009, 2011, 2013 Free Software Foundation, Inc.
|
2013-11-15 15:54:31 +01:00
|
|
|
|
* Coyrright (C) 2013 Werner Koch
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*
|
|
|
|
|
* 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
|
2007-07-04 19:49:40 +00:00
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* (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
|
2007-07-04 19:49:40 +00:00
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#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>
|
|
|
|
|
|
2003-06-18 19:56:13 +00:00
|
|
|
|
#include "gpg.h"
|
2003-06-05 07:14:21 +00:00
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "options.h"
|
|
|
|
|
#include "main.h" /*try_make_homedir ()*/
|
|
|
|
|
#include "packet.h"
|
|
|
|
|
#include "keyring.h"
|
2012-12-27 15:04:29 +01:00
|
|
|
|
#include "../kbx/keybox.h"
|
2011-02-04 12:57:53 +01:00
|
|
|
|
#include "keydb.h"
|
2003-06-05 07:14:21 +00:00
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
|
|
|
|
static int active_handles;
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
typedef enum
|
|
|
|
|
{
|
2003-06-05 07:14:21 +00:00
|
|
|
|
KEYDB_RESOURCE_TYPE_NONE = 0,
|
2012-12-27 15:04:29 +01:00
|
|
|
|
KEYDB_RESOURCE_TYPE_KEYRING,
|
|
|
|
|
KEYDB_RESOURCE_TYPE_KEYBOX
|
2011-04-29 15:07:11 +02:00
|
|
|
|
} KeydbResourceType;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
#define MAX_KEYDB_RESOURCES 40
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
struct resource_item
|
2010-04-23 11:36:59 +00:00
|
|
|
|
{
|
2003-06-05 07:14:21 +00:00
|
|
|
|
KeydbResourceType type;
|
|
|
|
|
union {
|
|
|
|
|
KEYRING_HANDLE kr;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
KEYBOX_HANDLE kb;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
} u;
|
|
|
|
|
void *token;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
|
|
|
|
static int used_resources;
|
|
|
|
|
static void *primary_keyring=NULL;
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
struct keydb_handle
|
|
|
|
|
{
|
2003-06-05 07:14:21 +00:00
|
|
|
|
int locked;
|
|
|
|
|
int found;
|
|
|
|
|
int current;
|
2011-04-29 15:07:11 +02:00
|
|
|
|
int used; /* Number of items in ACTIVE. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
struct resource_item active[MAX_KEYDB_RESOURCES];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
/* This is a simple cache used to return the last result of a
|
|
|
|
|
successful long kid 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 {
|
|
|
|
|
enum keyblock_cache_states state;
|
|
|
|
|
u32 kid[2];
|
|
|
|
|
iobuf_t iobuf; /* Image of the keyblock. */
|
|
|
|
|
u32 *sigstatus;
|
|
|
|
|
int pk_no;
|
|
|
|
|
int uid_no;
|
|
|
|
|
} keyblock_cache;
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
static int lock_all (KEYDB_HANDLE hd);
|
|
|
|
|
static void unlock_all (KEYDB_HANDLE hd);
|
|
|
|
|
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
static void
|
|
|
|
|
keyblock_cache_clear (void)
|
|
|
|
|
{
|
|
|
|
|
keyblock_cache.state = KEYBLOCK_CACHE_EMPTY;
|
|
|
|
|
xfree (keyblock_cache.sigstatus);
|
|
|
|
|
keyblock_cache.sigstatus = NULL;
|
|
|
|
|
iobuf_close (keyblock_cache.iobuf);
|
|
|
|
|
keyblock_cache.iobuf = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-12-27 15:04:29 +01:00
|
|
|
|
/* Handle the creation of a keyring or a keybox if it does not yet
|
|
|
|
|
exist. Take into acount that other processes might have the
|
|
|
|
|
keyring/keybox already locked. This lock check does not work if
|
|
|
|
|
the directory itself is not yet available. */
|
2006-04-19 11:26:11 +00:00
|
|
|
|
static int
|
2012-12-27 15:04:29 +01:00
|
|
|
|
maybe_create_keyring_or_box (char *filename, int is_box, int force)
|
2006-04-19 11:26:11 +00:00
|
|
|
|
{
|
2009-09-23 10:28:41 +00:00
|
|
|
|
dotlock_t lockhd = NULL;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
IOBUF iobuf;
|
|
|
|
|
int rc;
|
|
|
|
|
mode_t oldmask;
|
|
|
|
|
char *last_slash_in_filename;
|
2008-01-29 16:04:57 +00:00
|
|
|
|
int save_slash;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
|
|
|
|
|
/* 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. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!force)
|
2006-04-19 11:26:11 +00:00
|
|
|
|
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);
|
2008-01-29 16:04:57 +00:00
|
|
|
|
#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;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
*last_slash_in_filename = 0;
|
|
|
|
|
if (access(filename, F_OK))
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2006-04-19 11:26:11 +00:00
|
|
|
|
static int tried;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if (!tried)
|
|
|
|
|
{
|
|
|
|
|
tried = 1;
|
|
|
|
|
try_make_homedir (filename);
|
|
|
|
|
}
|
|
|
|
|
if (access (filename, F_OK))
|
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2008-01-30 14:26:57 +00:00
|
|
|
|
*last_slash_in_filename = save_slash;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-01-29 16:04:57 +00:00
|
|
|
|
*last_slash_in_filename = save_slash;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
|
|
|
|
|
/* 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. */
|
2011-09-28 15:41:58 +02:00
|
|
|
|
lockhd = dotlock_create (filename, 0);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if (!lockhd)
|
|
|
|
|
{
|
2012-12-27 15:04:29 +01:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2006-04-19 11:26:11 +00:00
|
|
|
|
/* 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)
|
2012-12-27 15:04:29 +01:00
|
|
|
|
log_info ("can't allocate lock for '%s': %s\n",
|
|
|
|
|
filename, gpg_strerror (rc));
|
2006-04-19 11:26:11 +00:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!force)
|
|
|
|
|
return gpg_error (GPG_ERR_ENOENT);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
else
|
2012-12-27 15:04:29 +01:00
|
|
|
|
return rc;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-09-23 14:43:58 +02:00
|
|
|
|
if ( dotlock_take (lockhd, -1) )
|
2006-04-19 11:26:11 +00:00
|
|
|
|
{
|
2012-12-27 15:04:29 +01:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2006-04-19 11:26:11 +00:00
|
|
|
|
/* This is something bad. Probably a stale lockfile. */
|
2012-12-27 15:04:29 +01:00
|
|
|
|
log_info ("can't lock '%s': %s\n", filename, gpg_strerror (rc));
|
2006-04-19 11:26:11 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now the real test while we are locked. */
|
2012-12-27 15:04:29 +01:00
|
|
|
|
if (!access (filename, F_OK))
|
2006-04-19 11:26:11 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
2010-04-01 13:24:55 +00:00
|
|
|
|
gpg_err_set_errno (EPERM);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
iobuf = iobuf_create (filename);
|
|
|
|
|
umask (oldmask);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!iobuf)
|
2006-04-19 11:26:11 +00:00
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2012-12-27 15:04:29 +01:00
|
|
|
|
if (is_box)
|
|
|
|
|
log_error (_("error creating keybox '%s': %s\n"),
|
|
|
|
|
filename, gpg_strerror (rc));
|
|
|
|
|
else
|
|
|
|
|
log_error (_("error creating keyring '%s': %s\n"),
|
|
|
|
|
filename, gpg_strerror (rc));
|
2006-04-19 11:26:11 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iobuf_close (iobuf);
|
|
|
|
|
/* Must invalidate that ugly cache */
|
2010-03-08 17:05:37 +00:00
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, filename);
|
2012-12-27 15:04:29 +01:00
|
|
|
|
|
|
|
|
|
/* Make sure that at least one record is in a new keybox file, so
|
|
|
|
|
that the detection magic will work the next time it is used. */
|
|
|
|
|
if (is_box)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = fopen (filename, "w");
|
|
|
|
|
if (!fp)
|
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rc = _keybox_write_header_blob (fp);
|
|
|
|
|
fclose (fp);
|
|
|
|
|
}
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
if (is_box)
|
|
|
|
|
log_error (_("error creating keybox '%s': %s\n"),
|
|
|
|
|
filename, gpg_strerror (rc));
|
|
|
|
|
else
|
|
|
|
|
log_error (_("error creating keyring '%s': %s\n"),
|
|
|
|
|
filename, gpg_strerror (rc));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!opt.quiet)
|
|
|
|
|
{
|
|
|
|
|
if (is_box)
|
|
|
|
|
log_info (_("keybox '%s' created\n"), filename);
|
|
|
|
|
else
|
|
|
|
|
log_info (_("keyring '%s' created\n"), filename);
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-19 11:26:11 +00:00
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (lockhd)
|
|
|
|
|
{
|
2011-09-23 14:43:58 +02:00
|
|
|
|
dotlock_release (lockhd);
|
|
|
|
|
dotlock_destroy (lockhd);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
/*
|
2012-12-27 15:04:29 +01:00
|
|
|
|
* Register a resource (keyring or aeybox). The first keyring or
|
|
|
|
|
* keybox which is added by this function is created if it does not
|
|
|
|
|
* exist. FLAGS are a combination of the KEYDB_RESOURCE_FLAG_
|
|
|
|
|
* constants as defined in keydb.h.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2012-12-27 15:04:29 +01:00
|
|
|
|
keydb_add_resource (const char *url, unsigned int flags)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2012-12-27 15:04:29 +01:00
|
|
|
|
static int any_registered;
|
2011-04-29 15:07:11 +02:00
|
|
|
|
const char *resname = url;
|
|
|
|
|
char *filename = NULL;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
int create;
|
|
|
|
|
int read_only = !!(flags&KEYDB_RESOURCE_FLAG_READONLY);
|
2011-04-29 15:07:11 +02:00
|
|
|
|
int rc = 0;
|
|
|
|
|
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
|
|
|
|
void *token;
|
|
|
|
|
|
2012-12-27 15:04:29 +01:00
|
|
|
|
/* Create the resource if it is the first registered one. */
|
|
|
|
|
create = (!read_only && !any_registered);
|
2011-04-29 15:07:11 +02:00
|
|
|
|
|
|
|
|
|
/* Do we have an URL?
|
2012-12-27 15:04:29 +01:00
|
|
|
|
* gnupg-ring:filename := this is a plain keyring.
|
|
|
|
|
* gnupg-kbx:filename := this is a keybox file.
|
2011-04-29 15:07:11 +02:00
|
|
|
|
* filename := See what is is, but create as plain keyring.
|
|
|
|
|
*/
|
2012-12-27 15:04:29 +01:00
|
|
|
|
if (strlen (resname) > 11 && !strncmp( resname, "gnupg-ring:", 11) )
|
2011-04-29 15:07:11 +02:00
|
|
|
|
{
|
2012-12-27 15:04:29 +01:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
|
|
|
|
resname += 11;
|
|
|
|
|
}
|
|
|
|
|
else if (strlen (resname) > 10 && !strncmp (resname, "gnupg-kbx:", 10) )
|
|
|
|
|
{
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
resname += 10;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
|
2012-12-27 15:04:29 +01:00
|
|
|
|
else if (strchr (resname, ':'))
|
|
|
|
|
{
|
|
|
|
|
log_error ("invalid key resource URL '%s'\n", url );
|
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
goto leave;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2012-12-27 15:04:29 +01:00
|
|
|
|
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
else
|
|
|
|
|
filename = xstrdup (resname);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
/* See whether we can determine the filetype. */
|
|
|
|
|
if (rt == KEYDB_RESOURCE_TYPE_NONE)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = fopen (filename, "rb");
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (fp)
|
|
|
|
|
{
|
|
|
|
|
u32 magic;
|
|
|
|
|
|
2012-12-27 15:04:29 +01:00
|
|
|
|
if (fread (&magic, 4, 1, fp) == 1 )
|
2011-04-29 15:07:11 +02:00
|
|
|
|
{
|
|
|
|
|
if (magic == 0x13579ace || magic == 0xce9a5713)
|
|
|
|
|
; /* GDBM magic - not anymore supported. */
|
2012-12-27 15:04:29 +01:00
|
|
|
|
else if (fread (&magic, 4, 1, fp) == 1
|
|
|
|
|
&& !memcmp (&magic, "\x01", 1)
|
|
|
|
|
&& fread (&magic, 4, 1, fp) == 1
|
|
|
|
|
&& !memcmp (&magic, "KBXf", 4))
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
2011-04-29 15:07:11 +02:00
|
|
|
|
else
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
else /* Maybe empty: assume keyring. */
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
|
|
|
|
|
2012-12-27 15:04:29 +01:00
|
|
|
|
fclose (fp);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2012-12-27 15:04:29 +01:00
|
|
|
|
else /* No file yet: create keybox. */
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
switch (rt)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("unknown type of key resource '%s'\n", url );
|
2011-04-29 15:07:11 +02:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
goto leave;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYRING:
|
2012-12-27 15:04:29 +01:00
|
|
|
|
rc = maybe_create_keyring_or_box (filename, create, 0);
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
goto leave;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (keyring_register_filename (filename, read_only, &token))
|
|
|
|
|
{
|
|
|
|
|
if (used_resources >= MAX_KEYDB_RESOURCES)
|
|
|
|
|
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
|
|
|
|
else
|
|
|
|
|
{
|
2012-12-27 15:04:29 +01:00
|
|
|
|
if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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. */
|
2012-12-27 15:04:29 +01:00
|
|
|
|
if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
|
2011-04-29 15:07:11 +02:00
|
|
|
|
primary_keyring = token;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
{
|
|
|
|
|
rc = maybe_create_keyring_or_box (filename, create, 1);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
/* FIXME: How do we register a read-only keybox? */
|
|
|
|
|
token = keybox_register_file (filename, 0);
|
|
|
|
|
if (token)
|
|
|
|
|
{
|
|
|
|
|
if (used_resources >= MAX_KEYDB_RESOURCES)
|
|
|
|
|
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
|
|
|
|
|
/* primary_keyring = token; */
|
|
|
|
|
all_resources[used_resources].type = rt;
|
|
|
|
|
all_resources[used_resources].u.kb = NULL; /* Not used here */
|
|
|
|
|
all_resources[used_resources].token = token;
|
|
|
|
|
|
|
|
|
|
/* FIXME: Do a compress run if needed and no other
|
|
|
|
|
user is currently using the keybox. */
|
|
|
|
|
|
|
|
|
|
used_resources++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Already registered. We will mark it as the primary key
|
|
|
|
|
if requested. */
|
|
|
|
|
/* FIXME: How to do that? Change the keybox interface? */
|
|
|
|
|
/* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
|
|
|
|
|
/* primary_keyring = token; */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
default:
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("resource type of '%s' not supported\n", url);
|
2011-04-29 15:07:11 +02:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-27 15:04:29 +01:00
|
|
|
|
/* fixme: check directory permissions and print a warning */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
leave:
|
|
|
|
|
if (rc)
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error (_("keyblock resource '%s': %s\n"), filename, gpg_strerror (rc));
|
2011-04-29 15:07:11 +02:00
|
|
|
|
else
|
2012-12-27 15:04:29 +01:00
|
|
|
|
any_registered = 1;
|
2011-04-29 15:07:11 +02:00
|
|
|
|
xfree (filename);
|
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KEYDB_HANDLE
|
2010-04-21 16:26:17 +00:00
|
|
|
|
keydb_new (void)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
KEYDB_HANDLE hd;
|
|
|
|
|
int i, j;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("keydb_new");
|
|
|
|
|
|
2006-04-19 11:26:11 +00:00
|
|
|
|
hd = xmalloc_clear (sizeof *hd);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->found = -1;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
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;
|
2010-04-23 11:36:59 +00:00
|
|
|
|
hd->active[j].u.kr = keyring_new (all_resources[i].token);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!hd->active[j].u.kr) {
|
2003-06-18 19:56:13 +00:00
|
|
|
|
xfree (hd);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return NULL; /* fixme: release all previously allocated handles*/
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
break;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
hd->active[j].type = all_resources[i].type;
|
|
|
|
|
hd->active[j].token = all_resources[i].token;
|
|
|
|
|
hd->active[j].u.kb = keybox_new (all_resources[i].token, 0);
|
|
|
|
|
if (!hd->active[j].u.kb)
|
|
|
|
|
{
|
|
|
|
|
xfree (hd);
|
|
|
|
|
return NULL; /* fixme: release all previously allocated handles*/
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
hd->used = j;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
active_handles++;
|
|
|
|
|
return hd;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
void
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_release (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_release (hd->active[i].u.kb);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
xfree (hd);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
s = keybox_get_resource_name (hd->active[idx].u.kb);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
return s? s: "";
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static int
|
2003-06-05 07:14:21 +00:00
|
|
|
|
lock_all (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
int i, rc = 0;
|
|
|
|
|
|
2012-12-27 15:04:29 +01:00
|
|
|
|
/* Fixme: This locking scheme may lead to a deadlock if the resources
|
|
|
|
|
are not added in the same order by all processes. We are
|
|
|
|
|
currently only allowing one resource so it is not a problem.
|
|
|
|
|
[Oops: Who claimed the latter]
|
|
|
|
|
|
|
|
|
|
To fix this we need to use a lock file to protect lock_all. */
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_lock (hd->active[i].u.kb, 1);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
2012-12-27 15:04:29 +01:00
|
|
|
|
/* Revert the already taken locks. */
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_lock (hd->active[i].u.kb, 0);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
else
|
|
|
|
|
hd->locked = 1;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
static void
|
|
|
|
|
unlock_all (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_lock (hd->active[i].u.kb, 0);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
hd->locked = 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
static gpg_error_t
|
2013-01-07 21:14:52 +01:00
|
|
|
|
parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
|
|
|
|
|
const u32 *sigstatus, kbnode_t *r_keyblock)
|
2012-12-28 14:03:16 +01:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
kbnode_t node, *tail;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
int in_cert, save_mode;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
u32 n_sigs;
|
2013-01-07 21:14:52 +01:00
|
|
|
|
int pk_count, uid_count;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
|
|
|
|
*r_keyblock = NULL;
|
|
|
|
|
|
|
|
|
|
pkt = xtrymalloc (sizeof *pkt);
|
|
|
|
|
if (!pkt)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
init_packet (pkt);
|
|
|
|
|
save_mode = set_packet_list_mode (0);
|
|
|
|
|
in_cert = 0;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
n_sigs = 0;
|
|
|
|
|
tail = NULL;
|
2013-01-07 21:14:52 +01:00
|
|
|
|
pk_count = uid_count = 0;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
while ((err = parse_packet (iobuf, pkt)) != -1)
|
|
|
|
|
{
|
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
|
|
|
|
|
{
|
|
|
|
|
free_packet (pkt);
|
|
|
|
|
init_packet (pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("parse_keyblock_image: read error: %s\n",
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_KEYRING);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (pkt->pkttype == PKT_COMPRESSED)
|
|
|
|
|
{
|
|
|
|
|
log_error ("skipped compressed packet in keybox blob\n");
|
|
|
|
|
free_packet(pkt);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (pkt->pkttype == PKT_RING_TRUST)
|
|
|
|
|
{
|
|
|
|
|
log_info ("skipped ring trust packet in keybox blob\n");
|
|
|
|
|
free_packet(pkt);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
2012-12-28 17:17:56 +01:00
|
|
|
|
log_error ("parse_keyblock_image: first packet in a keybox blob "
|
|
|
|
|
"is not a public key packet\n");
|
2012-12-28 14:03:16 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_INV_KEYRING);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| pkt->pkttype == PKT_SECRET_KEY))
|
|
|
|
|
{
|
2012-12-28 17:17:56 +01:00
|
|
|
|
log_error ("parse_keyblock_image: "
|
|
|
|
|
"multiple keyblocks in a keybox blob\n");
|
2012-12-28 14:03:16 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_INV_KEYRING);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
in_cert = 1;
|
|
|
|
|
|
2012-12-28 17:17:56 +01:00
|
|
|
|
if (pkt->pkttype == PKT_SIGNATURE && sigstatus)
|
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = pkt->pkt.signature;
|
|
|
|
|
|
|
|
|
|
n_sigs++;
|
|
|
|
|
if (n_sigs > sigstatus[0])
|
|
|
|
|
{
|
|
|
|
|
log_error ("parse_keyblock_image: "
|
|
|
|
|
"more signatures than found in the meta data\n");
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_KEYRING);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if (sigstatus[n_sigs])
|
|
|
|
|
{
|
|
|
|
|
sig->flags.checked = 1;
|
|
|
|
|
if (sigstatus[n_sigs] == 1 )
|
|
|
|
|
; /* missing key */
|
|
|
|
|
else if (sigstatus[n_sigs] == 2 )
|
|
|
|
|
; /* bad signature */
|
|
|
|
|
else if (sigstatus[n_sigs] < 0x10000000)
|
|
|
|
|
; /* bad flag */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sig->flags.valid = 1;
|
|
|
|
|
/* Fixme: Shall we set the expired flag here? */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
node = new_kbnode (pkt);
|
2013-01-07 21:14:52 +01:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
if (!keyblock)
|
|
|
|
|
keyblock = node;
|
|
|
|
|
else
|
2012-12-28 17:17:56 +01:00
|
|
|
|
*tail = node;
|
|
|
|
|
tail = &node->next;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
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. */
|
|
|
|
|
|
2012-12-28 17:17:56 +01:00
|
|
|
|
if (!err && sigstatus && n_sigs != sigstatus[0])
|
|
|
|
|
{
|
|
|
|
|
log_error ("parse_keyblock_image: signature count does not match\n");
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_KEYRING);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
if (err)
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
else
|
|
|
|
|
*r_keyblock = keyblock;
|
|
|
|
|
free_packet (pkt);
|
|
|
|
|
xfree (pkt);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
/*
|
|
|
|
|
* Return the last found keyring. Caller must free it.
|
|
|
|
|
* The returned keyblock has the kbode flag bit 0 set for the node with
|
2011-02-04 12:57:53 +01:00
|
|
|
|
* the public key used to locate the keyblock or flag bit 1 set for
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* the user ID node.
|
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
*ret_kb = NULL;
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_ARG);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
if (keyblock_cache.state == KEYBLOCK_CACHE_FILLED)
|
|
|
|
|
{
|
|
|
|
|
iobuf_seek (keyblock_cache.iobuf, 0);
|
|
|
|
|
err = parse_keyblock_image (keyblock_cache.iobuf,
|
|
|
|
|
keyblock_cache.pk_no,
|
|
|
|
|
keyblock_cache.uid_no,
|
|
|
|
|
keyblock_cache.sigstatus,
|
|
|
|
|
ret_kb);
|
|
|
|
|
if (err)
|
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
{
|
|
|
|
|
iobuf_t iobuf;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
u32 *sigstatus;
|
2013-01-07 21:14:52 +01:00
|
|
|
|
int pk_no, uid_no;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
2012-12-28 17:17:56 +01:00
|
|
|
|
err = keybox_get_keyblock (hd->active[hd->found].u.kb,
|
2013-01-07 21:14:52 +01:00
|
|
|
|
&iobuf, &pk_no, &uid_no, &sigstatus);
|
2012-12-28 14:03:16 +01:00
|
|
|
|
if (!err)
|
|
|
|
|
{
|
2013-01-07 21:14:52 +01:00
|
|
|
|
err = parse_keyblock_image (iobuf, pk_no, uid_no, sigstatus,
|
|
|
|
|
ret_kb);
|
2013-01-08 14:44:49 +01:00
|
|
|
|
if (!err && keyblock_cache.state == KEYBLOCK_CACHE_PREPARED)
|
|
|
|
|
{
|
|
|
|
|
keyblock_cache.state = KEYBLOCK_CACHE_FILLED;
|
|
|
|
|
keyblock_cache.sigstatus = sigstatus;
|
|
|
|
|
keyblock_cache.iobuf = iobuf;
|
|
|
|
|
keyblock_cache.pk_no = pk_no;
|
|
|
|
|
keyblock_cache.uid_no = uid_no;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
xfree (sigstatus);
|
|
|
|
|
iobuf_close (iobuf);
|
|
|
|
|
}
|
2012-12-28 14:03:16 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
if (keyblock_cache.state != KEYBLOCK_CACHE_FILLED)
|
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
|
|
|
|
/* Build a keyblock image from KEYBLOCK. Returns 0 on success and
|
2012-12-28 17:17:56 +01:00
|
|
|
|
only then stores a new iobuf object at R_IOBUF and a signature
|
|
|
|
|
status vecotor at R_SIGSTATUS. */
|
2012-12-28 14:03:16 +01:00
|
|
|
|
static gpg_error_t
|
2012-12-28 17:17:56 +01:00
|
|
|
|
build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
|
2012-12-28 14:03:16 +01:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
iobuf_t iobuf;
|
|
|
|
|
kbnode_t kbctx, node;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
u32 n_sigs;
|
|
|
|
|
u32 *sigstatus;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
|
|
|
|
*r_iobuf = NULL;
|
2013-11-15 15:54:31 +01:00
|
|
|
|
if (r_sigstatus)
|
|
|
|
|
*r_sigstatus = NULL;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
|
|
|
|
|
/* Allocate a vector for the signature cache. This is an array of
|
|
|
|
|
u32 values with the first value giving the number of elements to
|
|
|
|
|
follow and each element descriping the cache status of the
|
|
|
|
|
signature. */
|
2013-11-15 15:54:31 +01:00
|
|
|
|
if (r_sigstatus)
|
|
|
|
|
{
|
|
|
|
|
for (kbctx=NULL, n_sigs=0; (node = walk_kbnode (keyblock, &kbctx, 0));)
|
|
|
|
|
if (node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
n_sigs++;
|
|
|
|
|
sigstatus = xtrycalloc (1+n_sigs, sizeof *sigstatus);
|
|
|
|
|
if (!sigstatus)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
sigstatus = NULL;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
|
|
|
|
iobuf = iobuf_temp ();
|
2012-12-28 17:17:56 +01:00
|
|
|
|
for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
|
2012-12-28 14:03:16 +01:00
|
|
|
|
{
|
|
|
|
|
/* Make sure to use only packets valid on a keyblock. */
|
|
|
|
|
switch (node->pkt->pkttype)
|
|
|
|
|
{
|
|
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
|
case PKT_PUBLIC_SUBKEY:
|
|
|
|
|
case PKT_SIGNATURE:
|
|
|
|
|
case PKT_USER_ID:
|
|
|
|
|
case PKT_ATTRIBUTE:
|
|
|
|
|
/* Note that we don't want the ring trust packets. They are
|
|
|
|
|
not useful. */
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = build_packet (iobuf, node->pkt);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
iobuf_close (iobuf);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2012-12-28 17:17:56 +01:00
|
|
|
|
|
|
|
|
|
/* Build signature status vector. */
|
|
|
|
|
if (node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
|
|
|
|
|
n_sigs++;
|
2013-11-15 15:54:31 +01:00
|
|
|
|
/* Fixme: Detect the "missing key" status. */
|
|
|
|
|
if (sig->flags.checked && sigstatus)
|
2012-12-28 17:17:56 +01:00
|
|
|
|
{
|
|
|
|
|
if (sig->flags.valid)
|
|
|
|
|
{
|
|
|
|
|
if (!sig->expiredate)
|
|
|
|
|
sigstatus[n_sigs] = 0xffffffff;
|
|
|
|
|
else if (sig->expiredate < 0x1000000)
|
|
|
|
|
sigstatus[n_sigs] = 0x10000000;
|
|
|
|
|
else
|
|
|
|
|
sigstatus[n_sigs] = sig->expiredate;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
sigstatus[n_sigs] = 0x00000002; /* Bad signature. */
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-12-28 14:03:16 +01:00
|
|
|
|
}
|
2013-11-15 15:54:31 +01:00
|
|
|
|
if (sigstatus)
|
|
|
|
|
sigstatus[0] = n_sigs;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
|
|
|
|
*r_iobuf = iobuf;
|
2013-11-15 15:54:31 +01:00
|
|
|
|
if (r_sigstatus)
|
|
|
|
|
*r_sigstatus = sigstatus;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2011-04-29 15:07:11 +02:00
|
|
|
|
* Update the current keyblock with the keyblock KB
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
|
|
|
|
keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2013-11-15 15:54:31 +01:00
|
|
|
|
gpg_error_t err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_ARG);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (opt.dry_run)
|
|
|
|
|
return 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2013-11-15 15:54:31 +01:00
|
|
|
|
err = lock_all (hd);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2013-11-15 15:54:31 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL); /* oops */
|
2011-04-29 15:07:11 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYRING:
|
2013-11-15 15:54:31 +01:00
|
|
|
|
err = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
{
|
|
|
|
|
iobuf_t iobuf;
|
|
|
|
|
|
|
|
|
|
err = build_keyblock_image (kb, &iobuf, NULL);
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
err = keybox_update_keyblock (hd->active[hd->found].u.kb,
|
|
|
|
|
iobuf_get_temp_buffer (iobuf),
|
|
|
|
|
iobuf_get_temp_length (iobuf));
|
|
|
|
|
iobuf_close (iobuf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
unlock_all (hd);
|
2013-11-15 15:54:31 +01:00
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
|
|
|
|
* Insert a new KB into one of the resources.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
|
|
|
|
keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2012-12-28 14:03:16 +01:00
|
|
|
|
gpg_error_t err;
|
2011-04-29 15:07:11 +02:00
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_ARG);
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
err = lock_all (hd);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2011-04-29 15:07:11 +02:00
|
|
|
|
|
|
|
|
|
switch (hd->active[idx].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2012-12-28 14:03:16 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL); /* oops */
|
2011-04-29 15:07:11 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYRING:
|
2012-12-28 14:03:16 +01:00
|
|
|
|
err = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
{ /* We need to turn our kbnode_t list of packets into a proper
|
|
|
|
|
keyblock first. This is required by the OpenPGP key parser
|
|
|
|
|
included in the keybox code. Eventually we can change this
|
|
|
|
|
kludge to have the caller pass the image. */
|
|
|
|
|
iobuf_t iobuf;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
u32 *sigstatus;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
2012-12-28 17:17:56 +01:00
|
|
|
|
err = build_keyblock_image (kb, &iobuf, &sigstatus);
|
2012-12-28 14:03:16 +01:00
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
err = keybox_insert_keyblock (hd->active[idx].u.kb,
|
|
|
|
|
iobuf_get_temp_buffer (iobuf),
|
2012-12-28 17:17:56 +01:00
|
|
|
|
iobuf_get_temp_length (iobuf),
|
|
|
|
|
sigstatus);
|
|
|
|
|
xfree (sigstatus);
|
2012-12-28 14:03:16 +01:00
|
|
|
|
iobuf_close (iobuf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlock_all (hd);
|
2012-12-28 14:03:16 +01:00
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2011-04-29 15:07:11 +02:00
|
|
|
|
* Delete the current keyblock.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_delete_keyblock (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_ARG);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (opt.dry_run)
|
|
|
|
|
return 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
rc = lock_all (hd);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_delete (hd->active[hd->found].u.kb);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
unlock_all (hd);
|
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Locate the default writable key resource, so that the next
|
|
|
|
|
* operation (which is only relevant for inserts) will be done on this
|
2011-02-04 12:57:53 +01:00
|
|
|
|
* resource.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t rc;
|
2008-10-20 13:53:23 +00:00
|
|
|
|
|
|
|
|
|
(void)reserved;
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!hd)
|
2006-04-19 11:26:11 +00:00
|
|
|
|
return G10ERR_INV_ARG;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
/* If we have a primary set, try that one first */
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (primary_keyring)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[hd->current].type)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
if (keybox_is_writable (hd->active[hd->current].token))
|
|
|
|
|
return 0; /* found (hd->current is set to it) */
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Rebuild the caches of all key resources.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2006-04-19 11:26:11 +00:00
|
|
|
|
keydb_rebuild_caches (int noisy)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
int i, rc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
for (i=0; i < used_resources; i++)
|
|
|
|
|
{
|
2009-04-03 10:34:22 +00:00
|
|
|
|
if (!keyring_is_writable (all_resources[i].token))
|
|
|
|
|
continue;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
switch (all_resources[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYRING:
|
2006-04-19 11:26:11 +00:00
|
|
|
|
rc = keyring_rebuild_cache (all_resources[i].token,noisy);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (rc)
|
|
|
|
|
log_error (_("failed to rebuild keyring cache: %s\n"),
|
2006-04-19 11:26:11 +00:00
|
|
|
|
g10_errstr (rc));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
break;
|
2013-11-15 15:54:31 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
/* N/A. */
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* Start the next search on this handle right at the beginning
|
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_search_reset (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t rc = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_ARG);
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("keydb_search_reset");
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_search_reset (hd->active[i].u.kb);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
static void
|
|
|
|
|
dump_search_desc (const char *text, KEYDB_SEARCH_DESC *desc, size_t ndesc)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
for (n=0; n < ndesc; n++)
|
|
|
|
|
{
|
|
|
|
|
switch (desc[n].mode)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_SEARCH_MODE_NONE: s = "none"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_EXACT: s = "exact"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_SUBSTR: s = "substr"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAIL: s = "mail"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILSUB: s = "mailsub"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILEND: s = "mailend"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_WORDS: s = "words"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_SHORT_KID: s = "short_kid"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_LONG_KID: s = "long_kid"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FPR16: s = "fpr16"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FPR20: s = "fpr20"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FPR: s = "fpr"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER: s = "issuer"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER_SN: s = "issuer_sn"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_SN: s = "sn"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_SUBJECT: s = "subject"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_KEYGRIP: s = "keygrip"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FIRST: s = "first"; break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_NEXT: s = "next"; break;
|
|
|
|
|
default: s = "?"; break;
|
|
|
|
|
}
|
|
|
|
|
if (!n)
|
|
|
|
|
log_debug ("%s: mode=%s", text, s);
|
|
|
|
|
else
|
|
|
|
|
log_debug ("%*s mode=%s", (int)strlen (text), "", s);
|
|
|
|
|
if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
|
|
|
|
|
log_printf (" %08lX%08lX", (unsigned long)desc[n].u.kid[0],
|
|
|
|
|
(unsigned long)desc[n].u.kid[1]);
|
|
|
|
|
else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
|
|
|
|
|
log_printf (" %08lX", (unsigned long)desc[n].u.kid[1]);
|
|
|
|
|
else if (desc[n].mode == KEYDB_SEARCH_MODE_SUBSTR)
|
|
|
|
|
log_printf (" '%s'", desc[n].u.name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2011-04-29 15:07:11 +02:00
|
|
|
|
* 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.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2013-01-08 09:43:21 +01:00
|
|
|
|
keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
|
|
|
|
size_t ndesc, size_t *descindex)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t rc;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_ARG);
|
|
|
|
|
|
2013-01-07 16:51:24 +01:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("keydb_search enter");
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
if (DBG_CACHE)
|
|
|
|
|
dump_search_desc ("keydb_search", desc, ndesc);
|
|
|
|
|
|
|
|
|
|
if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID
|
|
|
|
|
&& keyblock_cache.state == KEYBLOCK_CACHE_FILLED
|
|
|
|
|
&& keyblock_cache.kid[0] == desc[0].u.kid[0]
|
|
|
|
|
&& keyblock_cache.kid[1] == desc[0].u.kid[1])
|
|
|
|
|
{
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("keydb_search leave (cached)");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
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;
|
2012-12-27 15:04:29 +01:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_search (hd->active[hd->current].u.kb, desc, ndesc);
|
|
|
|
|
break;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-04-29 15:07:11 +02:00
|
|
|
|
if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
|
|
|
|
|
{
|
|
|
|
|
/* EOF -> switch to next resource */
|
|
|
|
|
hd->current++;
|
|
|
|
|
}
|
|
|
|
|
else if (!rc)
|
|
|
|
|
hd->found = hd->current;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
|
rc = ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
|
|
|
|
|
? gpg_error (GPG_ERR_NOT_FOUND)
|
|
|
|
|
: rc);
|
|
|
|
|
|
|
|
|
|
keyblock_cache_clear ();
|
|
|
|
|
if (!rc && ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
|
|
|
|
|
{
|
|
|
|
|
keyblock_cache.state = KEYBLOCK_CACHE_PREPARED;
|
|
|
|
|
keyblock_cache.kid[0] = desc[0].u.kid[0];
|
|
|
|
|
keyblock_cache.kid[1] = desc[0].u.kid[1];
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-07 16:51:24 +01:00
|
|
|
|
if (DBG_CLOCK)
|
2013-01-08 14:44:49 +01:00
|
|
|
|
log_clock (rc? "keydb_search leave (not found)"
|
|
|
|
|
: "keydb_search leave (found)");
|
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
|
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_search_first (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_FIRST;
|
2013-01-08 09:43:21 +01:00
|
|
|
|
return keydb_search (hd, &desc, 1, NULL);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_search_next (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_NEXT;
|
2013-01-08 09:43:21 +01:00
|
|
|
|
return keydb_search (hd, &desc, 1, NULL);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
|
|
|
|
|
desc.u.kid[0] = kid[0];
|
|
|
|
|
desc.u.kid[1] = kid[1];
|
2013-01-08 09:43:21 +01:00
|
|
|
|
return keydb_search (hd, &desc, 1, NULL);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
|
|
|
|
|
{
|
2011-04-29 15:07:11 +02:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2011-04-29 15:07:11 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
|
|
|
|
memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
|
2013-01-08 09:43:21 +01:00
|
|
|
|
return keydb_search (hd, &desc, 1, NULL);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|