2003-06-05 07:14:21 +00:00
|
|
|
|
/* keyring.c - keyring file handling
|
2015-05-08 15:51:11 +02:00
|
|
|
|
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
|
|
|
|
* Copyright (C) 1997-2015 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 <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
2003-06-18 19:56:13 +00:00
|
|
|
|
#include "gpg.h"
|
2003-06-05 07:14:21 +00:00
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "keyring.h"
|
|
|
|
|
#include "packet.h"
|
2011-02-04 12:57:53 +01:00
|
|
|
|
#include "keydb.h"
|
2003-06-05 07:14:21 +00:00
|
|
|
|
#include "options.h"
|
|
|
|
|
#include "main.h" /*for check_key_signature()*/
|
|
|
|
|
#include "i18n.h"
|
2016-01-14 16:29:45 +01:00
|
|
|
|
#include "../kbx/keybox.h"
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
typedef struct keyring_resource *KR_RESOURCE;
|
|
|
|
|
struct keyring_resource
|
2009-04-03 10:34:22 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
struct keyring_resource *next;
|
2009-12-15 11:03:17 +00:00
|
|
|
|
int read_only;
|
2009-09-23 10:28:41 +00:00
|
|
|
|
dotlock_t lockhd;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
int is_locked;
|
|
|
|
|
int did_full_scan;
|
|
|
|
|
char fname[1];
|
|
|
|
|
};
|
2015-12-14 14:32:37 +01:00
|
|
|
|
typedef struct keyring_resource const * CONST_KR_RESOURCE;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
static KR_RESOURCE kr_resources;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
struct keyring_handle
|
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
CONST_KR_RESOURCE resource;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
struct {
|
2015-12-14 14:32:37 +01:00
|
|
|
|
CONST_KR_RESOURCE kr;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
IOBUF iobuf;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
int eof;
|
|
|
|
|
int error;
|
|
|
|
|
} current;
|
|
|
|
|
struct {
|
2015-12-14 14:32:37 +01:00
|
|
|
|
CONST_KR_RESOURCE kr;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
off_t offset;
|
|
|
|
|
size_t pk_no;
|
|
|
|
|
size_t uid_no;
|
|
|
|
|
unsigned int n_packets; /*used for delete and update*/
|
2015-05-08 15:51:11 +02:00
|
|
|
|
} found, saved_found;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
struct {
|
|
|
|
|
char *name;
|
|
|
|
|
char *pattern;
|
|
|
|
|
} word_match;
|
|
|
|
|
};
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* The number of extant handles. */
|
|
|
|
|
static int active_handles;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
static int do_copy (int mode, const char *fname, KBNODE root,
|
2003-06-05 07:14:21 +00:00
|
|
|
|
off_t start_offset, unsigned int n_packets );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* We keep a cache of entries that we have entered in the DB. This
|
|
|
|
|
includes not only public keys, but also subkeys.
|
|
|
|
|
|
|
|
|
|
Note: we'd like to keep the offset of the items that are present,
|
|
|
|
|
however, this doesn't work, because another concurrent GnuPG
|
|
|
|
|
process could modify the keyring. */
|
|
|
|
|
struct key_present {
|
|
|
|
|
struct key_present *next;
|
|
|
|
|
u32 kid[2];
|
|
|
|
|
};
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* For the hash table, we use separate chaining with linked lists.
|
|
|
|
|
This means that we have an array of N linked lists (buckets), which
|
|
|
|
|
is indexed by KEYID[1] mod N. Elements present in the keyring will
|
|
|
|
|
be on the list; elements not present in the keyring will not be on
|
|
|
|
|
the list.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
Note: since the hash table stores both present and not present
|
|
|
|
|
information, it cannot be used until we complete a full scan of the
|
|
|
|
|
keyring. This is indicated by key_present_hash_ready. */
|
|
|
|
|
typedef struct key_present **key_present_hash_t;
|
|
|
|
|
static key_present_hash_t key_present_hash;
|
|
|
|
|
static int key_present_hash_ready;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
#define KEY_PRESENT_HASH_BUCKETS 2048
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* Allocate a new value for a key present hash table. */
|
|
|
|
|
static struct key_present *
|
|
|
|
|
key_present_value_new (void)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
struct key_present *k;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
k = xmalloc_clear (sizeof *k);
|
|
|
|
|
return k;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* Allocate a new key present hash table. */
|
|
|
|
|
static key_present_hash_t
|
|
|
|
|
key_present_hash_new (void)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
struct key_present **tbl;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
tbl = xmalloc_clear (KEY_PRESENT_HASH_BUCKETS * sizeof *tbl);
|
|
|
|
|
return tbl;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* Return whether the value described by KID if it is in the hash
|
|
|
|
|
table. Otherwise, return NULL. */
|
|
|
|
|
static struct key_present *
|
|
|
|
|
key_present_hash_lookup (key_present_hash_t tbl, u32 *kid)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
struct key_present *k;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (k = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))]; k; k = k->next)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
|
|
|
|
|
return k;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* Add the key to the hash table TBL if it is not already present. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
static void
|
2015-12-14 14:32:37 +01:00
|
|
|
|
key_present_hash_update (key_present_hash_t tbl, u32 *kid)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
struct key_present *k;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (k = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))]; k; k = k->next)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
|
2015-12-14 14:32:37 +01:00
|
|
|
|
return;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
k = key_present_value_new ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
k->kid[0] = kid[0];
|
|
|
|
|
k->kid[1] = kid[1];
|
2015-12-14 14:32:37 +01:00
|
|
|
|
k->next = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))];
|
|
|
|
|
tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))] = k;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* Add all the keys (public and subkeys) present in the keyblock to
|
|
|
|
|
the hash TBL. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
static void
|
2015-12-14 14:32:37 +01:00
|
|
|
|
key_present_hash_update_from_kb (key_present_hash_t tbl, KBNODE node)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
for (; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
u32 aki[2];
|
|
|
|
|
keyid_from_pk (node->pkt->pkt.public_key, aki);
|
2015-12-14 14:32:37 +01:00
|
|
|
|
key_present_hash_update (tbl, aki);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-14 14:32:37 +01:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* Register a filename for plain keyring files. ptr is set to a
|
|
|
|
|
* pointer to be used to create a handles etc, or the already-issued
|
|
|
|
|
* pointer if it has already been registered. The function returns 1
|
|
|
|
|
* if a new keyring was registered.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2010-04-23 11:36:59 +00:00
|
|
|
|
keyring_register_filename (const char *fname, int read_only, void **ptr)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
KR_RESOURCE kr;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
if (active_handles)
|
2015-12-14 14:32:37 +01:00
|
|
|
|
/* There are open handles. */
|
|
|
|
|
BUG ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (kr=kr_resources; kr; kr = kr->next)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2007-08-24 09:34:39 +00:00
|
|
|
|
if (same_file_p (kr->fname, fname))
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2009-04-03 10:34:22 +00:00
|
|
|
|
/* Already registered. */
|
2009-12-15 11:03:17 +00:00
|
|
|
|
if (read_only)
|
|
|
|
|
kr->read_only = 1;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*ptr=kr;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-18 19:56:13 +00:00
|
|
|
|
kr = xmalloc (sizeof *kr + strlen (fname));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
strcpy (kr->fname, fname);
|
2009-12-15 11:03:17 +00:00
|
|
|
|
kr->read_only = read_only;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
kr->lockhd = NULL;
|
|
|
|
|
kr->is_locked = 0;
|
|
|
|
|
kr->did_full_scan = 0;
|
|
|
|
|
/* keep a list of all issued pointers */
|
2015-12-14 14:32:37 +01:00
|
|
|
|
kr->next = kr_resources;
|
|
|
|
|
kr_resources = kr;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
/* create the offset table the first time a function here is used */
|
2015-12-14 14:32:37 +01:00
|
|
|
|
if (!key_present_hash)
|
|
|
|
|
key_present_hash = key_present_hash_new ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
*ptr=kr;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keyring_is_writable (void *token)
|
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
KR_RESOURCE r = token;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2009-12-15 11:03:17 +00:00
|
|
|
|
return r? (r->read_only || !access (r->fname, W_OK)) : 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
/* Create a new handle for the resource associated with TOKEN.
|
2015-12-03 12:18:32 +01:00
|
|
|
|
On error NULL is returned and ERRNO is set.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
The returned handle must be released using keyring_release (). */
|
|
|
|
|
KEYRING_HANDLE
|
2010-04-23 11:36:59 +00:00
|
|
|
|
keyring_new (void *token)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
KEYRING_HANDLE hd;
|
2015-12-14 14:32:37 +01:00
|
|
|
|
KR_RESOURCE resource = token;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (resource);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2015-12-03 12:18:32 +01:00
|
|
|
|
hd = xtrycalloc (1, sizeof *hd);
|
|
|
|
|
if (!hd)
|
|
|
|
|
return hd;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->resource = resource;
|
|
|
|
|
active_handles++;
|
|
|
|
|
return hd;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
void
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keyring_release (KEYRING_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
if (!hd)
|
|
|
|
|
return;
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (active_handles > 0);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
active_handles--;
|
2003-06-18 19:56:13 +00:00
|
|
|
|
xfree (hd->word_match.name);
|
|
|
|
|
xfree (hd->word_match.pattern);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_close (hd->current.iobuf);
|
2003-06-18 19:56:13 +00:00
|
|
|
|
xfree (hd);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-05-08 15:51:11 +02:00
|
|
|
|
/* Save the current found state in HD for later retrieval by
|
|
|
|
|
keybox_pop_found_state. Only one state may be saved. */
|
|
|
|
|
void
|
|
|
|
|
keyring_push_found_state (KEYRING_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
hd->saved_found = hd->found;
|
|
|
|
|
hd->found.kr = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Restore the saved found state in HD. */
|
|
|
|
|
void
|
|
|
|
|
keyring_pop_found_state (KEYRING_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
hd->found = hd->saved_found;
|
|
|
|
|
hd->saved_found.kr = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
const char *
|
|
|
|
|
keyring_get_resource_name (KEYRING_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
if (!hd || !hd->resource)
|
|
|
|
|
return NULL;
|
|
|
|
|
return hd->resource->fname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2008-10-20 13:53:23 +00:00
|
|
|
|
* Lock the keyring with the given handle, or unlock if YES is false.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* We ignore the handle and lock all registered files.
|
|
|
|
|
*/
|
2011-02-04 12:57:53 +01:00
|
|
|
|
int
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keyring_lock (KEYRING_HANDLE hd, int yes)
|
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
KR_RESOURCE kr;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
int rc = 0;
|
|
|
|
|
|
2008-10-20 13:53:23 +00:00
|
|
|
|
(void)hd;
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (yes) {
|
|
|
|
|
/* first make sure the lock handles are created */
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (kr=kr_resources; kr; kr = kr->next) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!keyring_is_writable(kr))
|
|
|
|
|
continue;
|
|
|
|
|
if (!kr->lockhd) {
|
2011-09-28 15:41:58 +02:00
|
|
|
|
kr->lockhd = dotlock_create (kr->fname, 0);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!kr->lockhd) {
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info ("can't allocate lock for '%s'\n", kr->fname );
|
2015-01-22 12:06:11 +01:00
|
|
|
|
rc = GPG_ERR_GENERAL;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
/* and now set the locks */
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (kr=kr_resources; kr; kr = kr->next) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!keyring_is_writable(kr))
|
|
|
|
|
continue;
|
|
|
|
|
if (kr->is_locked)
|
2016-01-14 20:45:33 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_W32_SYSTEM
|
|
|
|
|
/* Under Windows we need to CloseHandle the file before we
|
|
|
|
|
* try to lock it. This is because another process might
|
|
|
|
|
* have taken the lock and is using keybox_file_rename to
|
|
|
|
|
* rename the base file. How if our dotlock_take below is
|
|
|
|
|
* waiting for the lock but we have the base file still
|
|
|
|
|
* open, keybox_file_rename will never succeed as we are
|
|
|
|
|
* in a deadlock. */
|
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0,
|
|
|
|
|
(char*)kr->fname);
|
|
|
|
|
#endif /*HAVE_W32_SYSTEM*/
|
|
|
|
|
if (dotlock_take (kr->lockhd, -1) ) {
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info ("can't lock '%s'\n", kr->fname );
|
2015-01-22 12:06:11 +01:00
|
|
|
|
rc = GPG_ERR_GENERAL;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else
|
2003-06-05 07:14:21 +00:00
|
|
|
|
kr->is_locked = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rc || !yes) {
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (kr=kr_resources; kr; kr = kr->next) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!keyring_is_writable(kr))
|
|
|
|
|
continue;
|
|
|
|
|
if (!kr->is_locked)
|
2016-01-14 20:45:33 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (dotlock_release (kr->lockhd))
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info ("can't unlock '%s'\n", kr->fname );
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else
|
2003-06-05 07:14:21 +00:00
|
|
|
|
kr->is_locked = 0;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2015-01-22 12:14:48 +01:00
|
|
|
|
* Return the last found keyblock. Caller must free it.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
|
|
|
|
|
{
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
int rc;
|
|
|
|
|
KBNODE keyblock = NULL, node, lastnode;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
IOBUF a;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
int in_cert = 0;
|
|
|
|
|
int pk_no = 0;
|
|
|
|
|
int uid_no = 0;
|
|
|
|
|
int save_mode;
|
|
|
|
|
|
|
|
|
|
if (ret_kb)
|
|
|
|
|
*ret_kb = NULL;
|
|
|
|
|
|
|
|
|
|
if (!hd->found.kr)
|
|
|
|
|
return -1; /* no successful search */
|
|
|
|
|
|
|
|
|
|
a = iobuf_open (hd->found.kr->fname);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if (!a)
|
|
|
|
|
{
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error(_("can't open '%s'\n"), hd->found.kr->fname);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
return GPG_ERR_KEYRING_OPEN;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
if (iobuf_seek (a, hd->found.offset) ) {
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("can't seek '%s'\n", hd->found.kr->fname);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_close(a);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
return GPG_ERR_KEYRING_OPEN;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-18 19:56:13 +00:00
|
|
|
|
pkt = xmalloc (sizeof *pkt);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
init_packet (pkt);
|
|
|
|
|
hd->found.n_packets = 0;;
|
|
|
|
|
lastnode = NULL;
|
|
|
|
|
save_mode = set_packet_list_mode(0);
|
|
|
|
|
while ((rc=parse_packet (a, pkt)) != -1) {
|
|
|
|
|
hd->found.n_packets++;
|
2015-01-22 12:06:11 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
free_packet (pkt);
|
|
|
|
|
init_packet (pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-01-22 16:36:28 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
|
2015-11-17 12:55:42 +01:00
|
|
|
|
{
|
|
|
|
|
if (in_cert)
|
|
|
|
|
/* It is not this key that is problematic, but the
|
|
|
|
|
following key. */
|
|
|
|
|
{
|
|
|
|
|
rc = 0;
|
|
|
|
|
hd->found.n_packets --;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Upper layer needs to handle this. */
|
2015-11-17 14:38:03 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2015-11-17 12:55:42 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (rc) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
log_error ("keyring_get_keyblock: read error: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc) );
|
|
|
|
|
rc = GPG_ERR_INV_KEYRING;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2015-02-09 15:46:00 +01:00
|
|
|
|
|
|
|
|
|
/* Filter allowed packets. */
|
|
|
|
|
switch (pkt->pkttype)
|
|
|
|
|
{
|
|
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
|
case PKT_PUBLIC_SUBKEY:
|
|
|
|
|
case PKT_SECRET_KEY:
|
|
|
|
|
case PKT_SECRET_SUBKEY:
|
|
|
|
|
case PKT_USER_ID:
|
|
|
|
|
case PKT_ATTRIBUTE:
|
|
|
|
|
case PKT_SIGNATURE:
|
|
|
|
|
break; /* Allowed per RFC. */
|
|
|
|
|
case PKT_RING_TRUST:
|
|
|
|
|
case PKT_OLD_COMMENT:
|
|
|
|
|
case PKT_COMMENT:
|
|
|
|
|
case PKT_GPG_CONTROL:
|
|
|
|
|
break; /* Allowed by us. */
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
log_error ("skipped packet of type %d in keyring\n",
|
|
|
|
|
(int)pkt->pkttype);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
free_packet(pkt);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
continue;
|
2015-02-09 15:46:00 +01:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| pkt->pkttype == PKT_SECRET_KEY)) {
|
|
|
|
|
hd->found.n_packets--; /* fix counter */
|
|
|
|
|
break; /* ready */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
in_cert = 1;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (pkt->pkttype == PKT_RING_TRUST)
|
2009-05-06 09:36:06 +00:00
|
|
|
|
{
|
2003-06-05 07:14:21 +00:00
|
|
|
|
/*(this code is duplicated after the loop)*/
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( lastnode
|
2003-06-05 07:14:21 +00:00
|
|
|
|
&& lastnode->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& (pkt->pkt.ring_trust->sigcache & 1) ) {
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/* This is a ring trust packet with a checked signature
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* status cache following directly a signature paket.
|
2009-05-06 09:36:06 +00:00
|
|
|
|
* Set the cache status into that signature packet. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
PKT_signature *sig = lastnode->pkt->pkt.signature;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
sig->flags.checked = 1;
|
|
|
|
|
sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
|
|
|
|
|
}
|
2009-05-06 09:36:06 +00:00
|
|
|
|
/* Reset LASTNODE, so that we set the cache status only from
|
|
|
|
|
* the ring trust packet immediately following a signature. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
lastnode = NULL;
|
2009-05-06 09:36:06 +00:00
|
|
|
|
free_packet(pkt);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
node = lastnode = new_kbnode (pkt);
|
|
|
|
|
if (!keyblock)
|
|
|
|
|
keyblock = node;
|
|
|
|
|
else
|
|
|
|
|
add_kbnode (keyblock, node);
|
|
|
|
|
switch (pkt->pkttype)
|
|
|
|
|
{
|
|
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
|
case PKT_PUBLIC_SUBKEY:
|
|
|
|
|
case PKT_SECRET_KEY:
|
|
|
|
|
case PKT_SECRET_SUBKEY:
|
|
|
|
|
if (++pk_no == hd->found.pk_no)
|
|
|
|
|
node->flag |= 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKT_USER_ID:
|
|
|
|
|
if (++uid_no == hd->found.uid_no)
|
|
|
|
|
node->flag |= 2;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-05-06 09:36:06 +00:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2003-06-18 19:56:13 +00:00
|
|
|
|
pkt = xmalloc (sizeof *pkt);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
init_packet(pkt);
|
|
|
|
|
}
|
|
|
|
|
set_packet_list_mode(save_mode);
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (rc == -1 && keyblock)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
rc = 0; /* got the entire keyblock */
|
|
|
|
|
|
|
|
|
|
if (rc || !ret_kb)
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
else {
|
2015-02-09 15:46:00 +01:00
|
|
|
|
/*(duplicated from the loop body)*/
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if ( pkt && pkt->pkttype == PKT_RING_TRUST
|
2011-02-04 12:57:53 +01:00
|
|
|
|
&& lastnode
|
2003-06-05 07:14:21 +00:00
|
|
|
|
&& lastnode->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& (pkt->pkt.ring_trust->sigcache & 1) ) {
|
|
|
|
|
PKT_signature *sig = lastnode->pkt->pkt.signature;
|
|
|
|
|
sig->flags.checked = 1;
|
|
|
|
|
sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
|
|
|
|
|
}
|
|
|
|
|
*ret_kb = keyblock;
|
|
|
|
|
}
|
|
|
|
|
free_packet (pkt);
|
2003-06-18 19:56:13 +00:00
|
|
|
|
xfree (pkt);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_close(a);
|
|
|
|
|
|
|
|
|
|
/* Make sure that future search operations fail immediately when
|
2011-02-04 12:57:53 +01:00
|
|
|
|
* we know that we are working on a invalid keyring
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
2015-01-22 12:06:11 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_INV_KEYRING)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->current.error = rc;
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (!hd->found.kr)
|
|
|
|
|
return -1; /* no successful prior search */
|
|
|
|
|
|
2009-12-15 11:03:17 +00:00
|
|
|
|
if (hd->found.kr->read_only)
|
2009-04-03 10:34:22 +00:00
|
|
|
|
return gpg_error (GPG_ERR_EACCES);
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!hd->found.n_packets) {
|
|
|
|
|
/* need to know the number of packets - do a dummy get_keyblock*/
|
|
|
|
|
rc = keyring_get_keyblock (hd, NULL);
|
|
|
|
|
if (rc) {
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
if (!hd->found.n_packets)
|
|
|
|
|
BUG ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The open iobuf isn't needed anymore and in fact is a problem when
|
|
|
|
|
it comes to renaming the keyring files on some operating systems,
|
|
|
|
|
so close it here */
|
|
|
|
|
iobuf_close(hd->current.iobuf);
|
|
|
|
|
hd->current.iobuf = NULL;
|
|
|
|
|
|
|
|
|
|
/* do the update */
|
2010-04-23 11:36:59 +00:00
|
|
|
|
rc = do_copy (3, hd->found.kr->fname, kb,
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->found.offset, hd->found.n_packets );
|
|
|
|
|
if (!rc) {
|
2015-12-14 14:32:37 +01:00
|
|
|
|
if (key_present_hash)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
key_present_hash_update_from_kb (key_present_hash, kb);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
/* better reset the found info */
|
|
|
|
|
hd->found.kr = NULL;
|
|
|
|
|
hd->found.offset = 0;
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
const char *fname;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
fname = NULL;
|
|
|
|
|
else if (hd->found.kr)
|
2009-04-03 10:34:22 +00:00
|
|
|
|
{
|
2003-06-05 07:14:21 +00:00
|
|
|
|
fname = hd->found.kr->fname;
|
2009-12-15 11:03:17 +00:00
|
|
|
|
if (hd->found.kr->read_only)
|
2009-04-03 10:34:22 +00:00
|
|
|
|
return gpg_error (GPG_ERR_EACCES);
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
else if (hd->current.kr)
|
2009-04-03 10:34:22 +00:00
|
|
|
|
{
|
2003-06-05 07:14:21 +00:00
|
|
|
|
fname = hd->current.kr->fname;
|
2009-12-15 11:03:17 +00:00
|
|
|
|
if (hd->current.kr->read_only)
|
2009-04-03 10:34:22 +00:00
|
|
|
|
return gpg_error (GPG_ERR_EACCES);
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else
|
2003-06-05 07:14:21 +00:00
|
|
|
|
fname = hd->resource? hd->resource->fname:NULL;
|
|
|
|
|
|
|
|
|
|
if (!fname)
|
2015-01-22 12:06:11 +01:00
|
|
|
|
return GPG_ERR_GENERAL;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2009-04-03 10:34:22 +00:00
|
|
|
|
/* Close this one otherwise we will lose the position for
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* a next search. Fixme: it would be better to adjust the position
|
|
|
|
|
* after the write opertions.
|
|
|
|
|
*/
|
|
|
|
|
iobuf_close (hd->current.iobuf);
|
|
|
|
|
hd->current.iobuf = NULL;
|
|
|
|
|
|
|
|
|
|
/* do the insert */
|
2010-04-23 11:36:59 +00:00
|
|
|
|
rc = do_copy (1, fname, kb, 0, 0 );
|
2015-12-14 14:32:37 +01:00
|
|
|
|
if (!rc && key_present_hash)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
key_present_hash_update_from_kb (key_present_hash, kb);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keyring_delete_keyblock (KEYRING_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (!hd->found.kr)
|
|
|
|
|
return -1; /* no successful prior search */
|
|
|
|
|
|
2009-12-15 11:03:17 +00:00
|
|
|
|
if (hd->found.kr->read_only)
|
2009-04-03 10:34:22 +00:00
|
|
|
|
return gpg_error (GPG_ERR_EACCES);
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!hd->found.n_packets) {
|
|
|
|
|
/* need to know the number of packets - do a dummy get_keyblock*/
|
|
|
|
|
rc = keyring_get_keyblock (hd, NULL);
|
|
|
|
|
if (rc) {
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
if (!hd->found.n_packets)
|
|
|
|
|
BUG ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* close this one otherwise we will lose the position for
|
|
|
|
|
* a next search. Fixme: it would be better to adjust the position
|
|
|
|
|
* after the write opertions.
|
|
|
|
|
*/
|
|
|
|
|
iobuf_close (hd->current.iobuf);
|
|
|
|
|
hd->current.iobuf = NULL;
|
|
|
|
|
|
|
|
|
|
/* do the delete */
|
2010-04-23 11:36:59 +00:00
|
|
|
|
rc = do_copy (2, hd->found.kr->fname, NULL,
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->found.offset, hd->found.n_packets );
|
|
|
|
|
if (!rc) {
|
|
|
|
|
/* better reset the found info */
|
|
|
|
|
hd->found.kr = NULL;
|
|
|
|
|
hd->found.offset = 0;
|
|
|
|
|
/* Delete is a rare operations, so we don't remove the keys
|
|
|
|
|
* from the offset table */
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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-02-04 12:57:53 +01:00
|
|
|
|
int
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keyring_search_reset (KEYRING_HANDLE hd)
|
|
|
|
|
{
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (hd);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
hd->current.kr = NULL;
|
|
|
|
|
iobuf_close (hd->current.iobuf);
|
|
|
|
|
hd->current.iobuf = NULL;
|
|
|
|
|
hd->current.eof = 0;
|
|
|
|
|
hd->current.error = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->found.kr = NULL;
|
|
|
|
|
hd->found.offset = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
prepare_search (KEYRING_HANDLE hd)
|
|
|
|
|
{
|
2015-01-22 16:36:28 +01:00
|
|
|
|
if (hd->current.error) {
|
|
|
|
|
/* If the last key was a legacy key, we simply ignore the error so that
|
|
|
|
|
we can easily use search_next. */
|
|
|
|
|
if (gpg_err_code (hd->current.error) == GPG_ERR_LEGACY_KEY)
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: last error was GPG_ERR_LEGACY_KEY, clearing\n",
|
|
|
|
|
__func__);
|
2015-01-22 16:36:28 +01:00
|
|
|
|
hd->current.error = 0;
|
2015-11-16 20:55:34 +01:00
|
|
|
|
}
|
2015-01-22 16:36:28 +01:00
|
|
|
|
else
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: returning last error: %s\n",
|
|
|
|
|
__func__, gpg_strerror (hd->current.error));
|
2015-01-22 16:36:28 +01:00
|
|
|
|
return hd->current.error; /* still in error state */
|
2015-11-16 20:55:34 +01:00
|
|
|
|
}
|
2015-01-22 16:36:28 +01:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
if (hd->current.kr && !hd->current.eof) {
|
|
|
|
|
if ( !hd->current.iobuf )
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: missing iobuf!\n", __func__);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
return GPG_ERR_GENERAL; /* Position invalid after a modify. */
|
2015-11-16 20:55:34 +01:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return 0; /* okay */
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!hd->current.kr && hd->current.eof)
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: EOF!\n", __func__);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return -1; /* still EOF */
|
2015-11-16 20:55:34 +01:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
if (!hd->current.kr) { /* start search with first keyring */
|
|
|
|
|
hd->current.kr = hd->resource;
|
|
|
|
|
if (!hd->current.kr) {
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: keyring not available!\n", __func__);
|
2016-02-15 11:05:29 +09:00
|
|
|
|
hd->current.eof = 1;
|
|
|
|
|
return -1; /* keyring not available */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (!hd->current.iobuf);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
else { /* EOF */
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: EOF\n", __func__);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
iobuf_close (hd->current.iobuf);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->current.iobuf = NULL;
|
|
|
|
|
hd->current.kr = NULL;
|
|
|
|
|
hd->current.eof = 1;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hd->current.eof = 0;
|
|
|
|
|
hd->current.iobuf = iobuf_open (hd->current.kr->fname);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if (!hd->current.iobuf)
|
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
hd->current.error = gpg_error_from_syserror ();
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error(_("can't open '%s'\n"), hd->current.kr->fname );
|
2003-06-18 19:56:13 +00:00
|
|
|
|
return hd->current.error;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* A map of the all characters valid used for word_match()
|
|
|
|
|
* Valid characters are in in this table converted to uppercase.
|
|
|
|
|
* because the upper 128 bytes have special meaning, we assume
|
|
|
|
|
* that they are all valid.
|
|
|
|
|
* Note: We must use numerical values here in case that this program
|
|
|
|
|
* will be converted to those little blue HAL9000s with their strange
|
|
|
|
|
* EBCDIC character set (user ids are UTF-8).
|
|
|
|
|
* wk 2000-04-13: Hmmm, does this really make sense, given the fact that
|
|
|
|
|
* we can run gpg now on a S/390 running GNU/Linux, where the code
|
|
|
|
|
* translation is done by the device drivers?
|
|
|
|
|
*/
|
|
|
|
|
static const byte word_match_chars[256] = {
|
|
|
|
|
/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
|
|
|
/* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 40 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
|
|
|
/* 48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
|
|
|
|
/* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
|
|
|
|
/* 58 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 60 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
|
|
|
/* 68 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
|
|
|
|
/* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
|
|
|
|
/* 78 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
/* 80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
|
|
|
|
/* 88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
|
|
|
|
/* 90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
|
|
|
|
/* 98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
|
|
|
|
/* a0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
|
|
|
|
/* a8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
|
|
|
|
/* b0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
|
|
|
|
/* b8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
|
|
|
|
/* c0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
|
|
|
|
/* c8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
|
|
|
|
/* d0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
|
|
|
|
/* d8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
|
|
|
|
/* e0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
|
|
|
|
/* e8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
|
|
|
|
/* f0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
|
|
|
|
/* f8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Do a word match (original user id starts with a '+').
|
|
|
|
|
* The pattern is already tokenized to a more suitable format:
|
|
|
|
|
* There are only the real words in it delimited by one space
|
|
|
|
|
* and all converted to uppercase.
|
|
|
|
|
*
|
|
|
|
|
* Returns: 0 if all words match.
|
|
|
|
|
*
|
|
|
|
|
* Note: This algorithm is a straightforward one and not very
|
|
|
|
|
* fast. It works for UTF-8 strings. The uidlen should
|
|
|
|
|
* be removed but due to the fact that old versions of
|
|
|
|
|
* pgp don't use UTF-8 we still use the length; this should
|
|
|
|
|
* be fixed in parse-packet (and replace \0 by some special
|
|
|
|
|
* UTF-8 encoding)
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
word_match( const byte *uid, size_t uidlen, const byte *pattern )
|
|
|
|
|
{
|
|
|
|
|
size_t wlen, n;
|
|
|
|
|
const byte *p;
|
|
|
|
|
const byte *s;
|
|
|
|
|
|
|
|
|
|
for( s=pattern; *s; ) {
|
|
|
|
|
do {
|
|
|
|
|
/* skip leading delimiters */
|
|
|
|
|
while( uidlen && !word_match_chars[*uid] )
|
|
|
|
|
uid++, uidlen--;
|
|
|
|
|
/* get length of the word */
|
|
|
|
|
n = uidlen; p = uid;
|
|
|
|
|
while( n && word_match_chars[*p] )
|
|
|
|
|
p++, n--;
|
|
|
|
|
wlen = p - uid;
|
|
|
|
|
/* and compare against the current word from pattern */
|
|
|
|
|
for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
|
|
|
|
|
if( word_match_chars[*p] != s[n] )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if( n == wlen && (s[n] == ' ' || !s[n]) )
|
|
|
|
|
break; /* found */
|
|
|
|
|
uid += wlen;
|
|
|
|
|
uidlen -= wlen;
|
|
|
|
|
} while( uidlen );
|
|
|
|
|
if( !uidlen )
|
|
|
|
|
return -1; /* not found */
|
|
|
|
|
|
|
|
|
|
/* advance to next word in pattern */
|
|
|
|
|
for(; *s != ' ' && *s ; s++ )
|
|
|
|
|
;
|
|
|
|
|
if( *s )
|
|
|
|
|
s++ ;
|
|
|
|
|
}
|
|
|
|
|
return 0; /* found */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* prepare word word_match; that is parse the name and
|
|
|
|
|
* build the pattern.
|
|
|
|
|
* caller has to free the returned pattern
|
|
|
|
|
*/
|
|
|
|
|
static char*
|
|
|
|
|
prepare_word_match (const byte *name)
|
|
|
|
|
{
|
|
|
|
|
byte *pattern, *p;
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
/* the original length is always enough for the pattern */
|
2006-04-19 11:26:11 +00:00
|
|
|
|
p = pattern = xmalloc(strlen(name)+1);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
do {
|
|
|
|
|
/* skip leading delimiters */
|
|
|
|
|
while( *name && !word_match_chars[*name] )
|
|
|
|
|
name++;
|
|
|
|
|
/* copy as long as we don't have a delimiter and convert
|
|
|
|
|
* to uppercase.
|
|
|
|
|
* fixme: how can we handle utf8 uppercasing */
|
|
|
|
|
for( ; *name && (c=word_match_chars[*name]); name++ )
|
|
|
|
|
*p++ = c;
|
|
|
|
|
*p++ = ' '; /* append pattern delimiter */
|
|
|
|
|
} while( *name );
|
|
|
|
|
p[-1] = 0; /* replace last pattern delimiter by EOS */
|
|
|
|
|
|
|
|
|
|
return pattern;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
compare_name (int mode, const char *name, const char *uid, size_t uidlen)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
const char *s, *se;
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (mode == KEYDB_SEARCH_MODE_EXACT) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
for (i=0; name[i] && uidlen; i++, uidlen--)
|
|
|
|
|
if (uid[i] != name[i])
|
|
|
|
|
break;
|
|
|
|
|
if (!uidlen && !name[i])
|
|
|
|
|
return 0; /* found */
|
|
|
|
|
}
|
|
|
|
|
else if (mode == KEYDB_SEARCH_MODE_SUBSTR) {
|
|
|
|
|
if (ascii_memistr( uid, uidlen, name ))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else if ( mode == KEYDB_SEARCH_MODE_MAIL
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|| mode == KEYDB_SEARCH_MODE_MAILSUB
|
|
|
|
|
|| mode == KEYDB_SEARCH_MODE_MAILEND) {
|
|
|
|
|
for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
|
|
|
|
|
;
|
|
|
|
|
if (i < uidlen) {
|
|
|
|
|
/* skip opening delim and one char and look for the closing one*/
|
|
|
|
|
s++; i++;
|
|
|
|
|
for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
|
|
|
|
|
;
|
|
|
|
|
if (i < uidlen) {
|
|
|
|
|
i = se - s;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (mode == KEYDB_SEARCH_MODE_MAIL) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if( strlen(name)-2 == i
|
|
|
|
|
&& !ascii_memcasecmp( s, name+1, i) )
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (mode == KEYDB_SEARCH_MODE_MAILSUB) {
|
|
|
|
|
if( ascii_memistr( s, i, name ) )
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else { /* email from end */
|
|
|
|
|
/* nyi */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (mode == KEYDB_SEARCH_MODE_WORDS)
|
|
|
|
|
return word_match (uid, uidlen, name);
|
|
|
|
|
else
|
|
|
|
|
BUG();
|
|
|
|
|
|
|
|
|
|
return -1; /* not found */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* Search through the keyring(s), starting at the current position,
|
|
|
|
|
* for a keyblock which contains one of the keys described in the DESC array.
|
|
|
|
|
*/
|
2011-02-04 12:57:53 +01:00
|
|
|
|
int
|
2003-06-05 07:14:21 +00:00
|
|
|
|
keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
2015-11-17 14:38:03 +01:00
|
|
|
|
size_t ndesc, size_t *descindex, int ignore_legacy)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
PACKET pkt;
|
|
|
|
|
int save_mode;
|
|
|
|
|
off_t offset, main_offset;
|
|
|
|
|
size_t n;
|
|
|
|
|
int need_uid, need_words, need_keyid, need_fpr, any_skip;
|
|
|
|
|
int pk_no, uid_no;
|
|
|
|
|
int initial_skip;
|
2015-11-11 18:26:53 +01:00
|
|
|
|
int scanned_from_start;
|
2015-12-14 14:32:37 +01:00
|
|
|
|
int use_key_present_hash;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
PKT_user_id *uid = NULL;
|
|
|
|
|
PKT_public_key *pk = NULL;
|
|
|
|
|
u32 aki[2];
|
|
|
|
|
|
|
|
|
|
/* figure out what information we need */
|
|
|
|
|
need_uid = need_words = need_keyid = need_fpr = any_skip = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=0; n < ndesc; n++)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (desc[n].mode)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_EXACT:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
case KEYDB_SEARCH_MODE_SUBSTR:
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAIL:
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILSUB:
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILEND:
|
|
|
|
|
need_uid = 1;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_WORDS:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
need_uid = 1;
|
|
|
|
|
need_words = 1;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_SHORT_KID:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
case KEYDB_SEARCH_MODE_LONG_KID:
|
|
|
|
|
need_keyid = 1;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_FPR16:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
case KEYDB_SEARCH_MODE_FPR20:
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_FPR:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
need_fpr = 1;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FIRST:
|
|
|
|
|
/* always restart the search in this mode */
|
|
|
|
|
keyring_search_reset (hd);
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (desc[n].skipfnc)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
any_skip = 1;
|
|
|
|
|
need_keyid = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: need_uid = %d; need_words = %d; need_keyid = %d; need_fpr = %d; any_skip = %d\n",
|
|
|
|
|
__func__, need_uid, need_words, need_keyid, need_fpr, any_skip);
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
rc = prepare_search (hd);
|
|
|
|
|
if (rc)
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: prepare_search failed: %s (%d)\n",
|
|
|
|
|
__func__, gpg_strerror (rc), gpg_err_code (rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
use_key_present_hash = !!key_present_hash;
|
|
|
|
|
if (!use_key_present_hash)
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: no offset table.\n", __func__);
|
|
|
|
|
}
|
2015-12-14 14:32:37 +01:00
|
|
|
|
else if (!key_present_hash_ready)
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: initializing offset table. (need_keyid: %d => 1)\n",
|
|
|
|
|
__func__, need_keyid);
|
|
|
|
|
need_keyid = 1;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
|
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
struct key_present *oi;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: look up by long key id, checking cache\n", __func__);
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
oi = key_present_hash_lookup (key_present_hash, desc[0].u.kid);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (!oi)
|
|
|
|
|
{ /* We know that we don't have this key */
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: cache says not present\n", __func__);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->found.kr = NULL;
|
|
|
|
|
hd->current.eof = 1;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
/* We could now create a positive search status and return.
|
2011-02-04 12:57:53 +01:00
|
|
|
|
* However the problem is that another instance of gpg may
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* have changed the keyring so that the offsets are not valid
|
2011-02-04 12:57:53 +01:00
|
|
|
|
* anymore - therefore we don't do it
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (need_words)
|
|
|
|
|
{
|
|
|
|
|
const char *name = NULL;
|
|
|
|
|
|
|
|
|
|
log_debug ("word search mode does not yet work\n");
|
|
|
|
|
/* FIXME: here is a long standing bug in our function and in addition we
|
|
|
|
|
just use the first search description */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=0; n < ndesc && !name; n++)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
name = desc[n].u.name;
|
|
|
|
|
}
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (name);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
/* name changed */
|
2003-06-18 19:56:13 +00:00
|
|
|
|
xfree (hd->word_match.name);
|
|
|
|
|
xfree (hd->word_match.pattern);
|
|
|
|
|
hd->word_match.name = xstrdup (name);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->word_match.pattern = prepare_word_match (name);
|
|
|
|
|
}
|
2009-06-24 14:03:09 +00:00
|
|
|
|
/* name = hd->word_match.pattern; */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init_packet(&pkt);
|
|
|
|
|
save_mode = set_packet_list_mode(0);
|
|
|
|
|
|
|
|
|
|
hd->found.kr = NULL;
|
|
|
|
|
main_offset = 0;
|
|
|
|
|
pk_no = uid_no = 0;
|
|
|
|
|
initial_skip = 1; /* skip until we see the start of a keyblock */
|
2015-11-11 18:26:53 +01:00
|
|
|
|
scanned_from_start = iobuf_tell (hd->current.iobuf) == 0;
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: %ssearching from start of resource.\n",
|
|
|
|
|
__func__, scanned_from_start ? "" : "not ");
|
2015-11-17 14:38:03 +01:00
|
|
|
|
while (1)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
byte afp[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t an;
|
|
|
|
|
|
2015-11-17 14:38:03 +01:00
|
|
|
|
rc = search_packet (hd->current.iobuf, &pkt, &offset, need_uid);
|
|
|
|
|
if (ignore_legacy && gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
|
|
|
|
|
{
|
|
|
|
|
free_packet (&pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (rc)
|
|
|
|
|
break;
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
main_offset = offset;
|
|
|
|
|
pk_no = uid_no = 0;
|
|
|
|
|
initial_skip = 0;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (initial_skip)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
free_packet (&pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
pk = NULL;
|
|
|
|
|
uid = NULL;
|
|
|
|
|
if ( pkt.pkttype == PKT_PUBLIC_KEY
|
2010-09-06 19:57:42 +00:00
|
|
|
|
|| pkt.pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| pkt.pkttype == PKT_SECRET_KEY
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|| pkt.pkttype == PKT_SECRET_SUBKEY)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
pk = pkt.pkt.public_key;
|
|
|
|
|
++pk_no;
|
|
|
|
|
|
|
|
|
|
if (need_fpr) {
|
|
|
|
|
fingerprint_from_pk (pk, afp, &an);
|
|
|
|
|
while (an < 20) /* fill up to 20 bytes */
|
|
|
|
|
afp[an++] = 0;
|
|
|
|
|
}
|
|
|
|
|
if (need_keyid)
|
|
|
|
|
keyid_from_pk (pk, aki);
|
|
|
|
|
|
2015-12-14 14:32:37 +01:00
|
|
|
|
if (use_key_present_hash
|
|
|
|
|
&& !key_present_hash_ready
|
|
|
|
|
&& scanned_from_start)
|
|
|
|
|
key_present_hash_update (key_present_hash, aki);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else if (pkt.pkttype == PKT_USER_ID)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
uid = pkt.pkt.user_id;
|
|
|
|
|
++uid_no;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=0; n < ndesc; n++)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
switch (desc[n].mode) {
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_NONE:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
BUG ();
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_EXACT:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
case KEYDB_SEARCH_MODE_SUBSTR:
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAIL:
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILSUB:
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILEND:
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_WORDS:
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if ( uid && !compare_name (desc[n].mode,
|
|
|
|
|
desc[n].u.name,
|
2011-02-04 12:57:53 +01:00
|
|
|
|
uid->name, uid->len))
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_SHORT_KID:
|
2010-09-06 19:57:42 +00:00
|
|
|
|
if (pk && desc[n].u.kid[1] == aki[1])
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_LONG_KID:
|
2010-09-06 19:57:42 +00:00
|
|
|
|
if (pk && desc[n].u.kid[0] == aki[0]
|
2003-06-05 07:14:21 +00:00
|
|
|
|
&& desc[n].u.kid[1] == aki[1])
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FPR16:
|
2010-09-06 19:57:42 +00:00
|
|
|
|
if (pk && !memcmp (desc[n].u.fpr, afp, 16))
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FPR20:
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_FPR:
|
2010-09-06 19:57:42 +00:00
|
|
|
|
if (pk && !memcmp (desc[n].u.fpr, afp, 20))
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_FIRST:
|
2010-09-06 19:57:42 +00:00
|
|
|
|
if (pk)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_NEXT:
|
2010-09-06 19:57:42 +00:00
|
|
|
|
if (pk)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
default:
|
2015-01-22 12:06:11 +01:00
|
|
|
|
rc = GPG_ERR_INV_ARG;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free_packet (&pkt);
|
|
|
|
|
continue;
|
|
|
|
|
found:
|
2015-11-17 12:56:55 +01:00
|
|
|
|
if (rc)
|
|
|
|
|
goto real_found;
|
|
|
|
|
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
2015-11-27 17:59:52 +01:00
|
|
|
|
log_debug ("%s: packet starting at offset %lld matched descriptor %zu\n"
|
|
|
|
|
, __func__, (long long)offset, n);
|
2015-11-16 20:55:34 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
/* Record which desc we matched on. Note this value is only
|
|
|
|
|
meaningful if this function returns with no errors. */
|
|
|
|
|
if(descindex)
|
|
|
|
|
*descindex=n;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=any_skip?0:ndesc; n < ndesc; n++)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
if (desc[n].skipfnc
|
2015-09-14 11:27:43 +02:00
|
|
|
|
&& desc[n].skipfnc (desc[n].skipfncvalue, aki, uid_no))
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: skipping match: desc %zd's skip function returned TRUE\n",
|
|
|
|
|
__func__, n);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
if (n == ndesc)
|
|
|
|
|
goto real_found;
|
|
|
|
|
free_packet (&pkt);
|
|
|
|
|
}
|
|
|
|
|
real_found:
|
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
2016-01-09 11:28:42 +01:00
|
|
|
|
log_debug ("%s: returning success\n", __func__);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->found.offset = main_offset;
|
|
|
|
|
hd->found.kr = hd->current.kr;
|
2010-09-06 19:57:42 +00:00
|
|
|
|
hd->found.pk_no = pk? pk_no : 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->found.uid_no = uid? uid_no : 0;
|
|
|
|
|
}
|
|
|
|
|
else if (rc == -1)
|
|
|
|
|
{
|
2015-11-16 20:55:34 +01:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: no matches (EOF)\n", __func__);
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
hd->current.eof = 1;
|
|
|
|
|
/* if we scanned all keyrings, we are sure that
|
|
|
|
|
* all known key IDs are in our offtbl, mark that. */
|
2015-12-14 14:32:37 +01:00
|
|
|
|
if (use_key_present_hash
|
|
|
|
|
&& !key_present_hash_ready
|
|
|
|
|
&& scanned_from_start)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-12-14 14:32:37 +01:00
|
|
|
|
KR_RESOURCE kr;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
/* First set the did_full_scan flag for this keyring. */
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (kr=kr_resources; kr; kr = kr->next)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (hd->resource == kr)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
kr->did_full_scan = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Then check whether all flags are set and if so, mark the
|
|
|
|
|
offtbl ready */
|
2015-12-14 14:32:37 +01:00
|
|
|
|
for (kr=kr_resources; kr; kr = kr->next)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!kr->did_full_scan)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!kr)
|
2015-12-14 14:32:37 +01:00
|
|
|
|
key_present_hash_ready = 1;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else
|
2015-11-16 20:55:34 +01:00
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: error encountered during search: %s (%d)\n",
|
|
|
|
|
__func__, gpg_strerror (rc), rc);
|
|
|
|
|
hd->current.error = rc;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
free_packet(&pkt);
|
|
|
|
|
set_packet_list_mode(save_mode);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
create_tmp_file (const char *template,
|
2006-04-19 11:26:11 +00:00
|
|
|
|
char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2016-01-14 16:29:45 +01:00
|
|
|
|
gpg_error_t err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
mode_t oldmask;
|
|
|
|
|
|
2016-01-14 16:29:45 +01:00
|
|
|
|
err = keybox_tmp_names (template, 1, r_bakfname, r_tmpfname);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2016-01-14 16:29:45 +01:00
|
|
|
|
/* Create the temp file with limited access. Note that the umask
|
|
|
|
|
call is not anymore needed because iobuf_create now takes care of
|
|
|
|
|
it. However, it does not harm and thus we keep it. */
|
|
|
|
|
oldmask = umask (077);
|
|
|
|
|
if (is_secured_filename (*r_tmpfname))
|
|
|
|
|
{
|
|
|
|
|
*r_fp = NULL;
|
|
|
|
|
gpg_err_set_errno (EPERM);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2016-01-14 16:29:45 +01:00
|
|
|
|
else
|
|
|
|
|
*r_fp = iobuf_create (*r_tmpfname, 1);
|
|
|
|
|
umask (oldmask);
|
|
|
|
|
if (!*r_fp)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error (_("can't create '%s': %s\n"), *r_tmpfname, gpg_strerror (err));
|
|
|
|
|
xfree (*r_tmpfname);
|
|
|
|
|
*r_tmpfname = NULL;
|
|
|
|
|
xfree (*r_bakfname);
|
|
|
|
|
*r_bakfname = NULL;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2016-01-14 16:29:45 +01:00
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-04-23 11:36:59 +00:00
|
|
|
|
rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2009-04-01 13:23:27 +00:00
|
|
|
|
int rc = 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2009-04-01 13:23:27 +00:00
|
|
|
|
/* Invalidate close caches. */
|
2010-03-08 17:05:37 +00:00
|
|
|
|
if (iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ))
|
2009-04-01 13:23:27 +00:00
|
|
|
|
{
|
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2010-03-08 17:05:37 +00:00
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname );
|
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
/* First make a backup file. */
|
2016-01-14 16:50:15 +01:00
|
|
|
|
rc = keybox_file_rename (fname, bakfname);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto fail;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
/* then rename the file */
|
2016-01-14 16:50:15 +01:00
|
|
|
|
rc = keybox_file_rename (tmpfname, fname);
|
|
|
|
|
if (rc)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-04-19 11:26:11 +00:00
|
|
|
|
register_secured_file (fname);
|
2009-04-01 13:23:27 +00:00
|
|
|
|
goto fail;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now make sure the file has the same permissions as the original */
|
|
|
|
|
#ifndef HAVE_DOSISH_SYSTEM
|
|
|
|
|
{
|
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
|
|
statbuf.st_mode=S_IRUSR | S_IWUSR;
|
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
if (!stat (bakfname, &statbuf) && !chmod (fname, statbuf.st_mode))
|
2003-06-05 07:14:21 +00:00
|
|
|
|
;
|
|
|
|
|
else
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("WARNING: unable to restore permissions to '%s': %s",
|
2009-04-01 13:23:27 +00:00
|
|
|
|
fname, strerror(errno));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return 0;
|
2009-04-01 13:23:27 +00:00
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2006-04-19 11:26:11 +00:00
|
|
|
|
write_keyblock (IOBUF fp, KBNODE keyblock)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
KBNODE kbctx = NULL, node;
|
|
|
|
|
int rc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
|
|
|
|
while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (node->pkt->pkttype == PKT_RING_TRUST)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
continue; /* we write it later on our own */
|
|
|
|
|
|
|
|
|
|
if ( (rc = build_packet (fp, node->pkt) ))
|
|
|
|
|
{
|
|
|
|
|
log_error ("build_packet(%d) failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
node->pkt->pkttype, gpg_strerror (rc) );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (node->pkt->pkttype == PKT_SIGNATURE)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{ /* always write a signature cache packet */
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
unsigned int cacheval = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
|
|
|
|
if (sig->flags.checked)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
cacheval |= 1;
|
|
|
|
|
if (sig->flags.valid)
|
|
|
|
|
cacheval |= 2;
|
|
|
|
|
}
|
|
|
|
|
iobuf_put (fp, 0xb0); /* old style packet 12, 1 byte len*/
|
|
|
|
|
iobuf_put (fp, 2); /* 2 bytes */
|
|
|
|
|
iobuf_put (fp, 0); /* unused */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (iobuf_put (fp, cacheval))
|
2006-04-19 11:26:11 +00:00
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2006-04-19 11:26:11 +00:00
|
|
|
|
log_error ("writing sigcache packet failed\n");
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2003-06-05 07:14:21 +00:00
|
|
|
|
* Walk over all public keyrings, check the signatures and replace the
|
|
|
|
|
* keyring with a new one where the signature cache is then updated.
|
|
|
|
|
* This is only done for the public keyrings.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2006-04-19 11:26:11 +00:00
|
|
|
|
keyring_rebuild_cache (void *token,int noisy)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
KEYRING_HANDLE hd;
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
KBNODE keyblock = NULL, node;
|
|
|
|
|
const char *lastresname = NULL, *resname;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
IOBUF tmpfp = NULL;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
char *tmpfilename = NULL;
|
|
|
|
|
char *bakfilename = NULL;
|
|
|
|
|
int rc;
|
|
|
|
|
ulong count = 0, sigcount = 0;
|
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
hd = keyring_new (token);
|
2015-12-03 12:18:32 +01:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error_from_syserror ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_FIRST;
|
|
|
|
|
|
|
|
|
|
rc=keyring_lock (hd, 1);
|
|
|
|
|
if(rc)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
2015-01-22 16:36:28 +01:00
|
|
|
|
for (;;)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-11-17 14:38:03 +01:00
|
|
|
|
rc = keyring_search (hd, &desc, 1, NULL, 0);
|
|
|
|
|
if (rc)
|
2015-01-22 16:36:28 +01:00
|
|
|
|
break; /* ready. */
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_NEXT;
|
|
|
|
|
resname = keyring_get_resource_name (hd);
|
|
|
|
|
if (lastresname != resname )
|
|
|
|
|
{ /* we have switched to a new keyring - commit changes */
|
|
|
|
|
if (tmpfp)
|
|
|
|
|
{
|
|
|
|
|
if (iobuf_close (tmpfp))
|
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("error closing '%s': %s\n",
|
2003-06-05 07:14:21 +00:00
|
|
|
|
tmpfilename, strerror (errno));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
/* because we have switched resources, we can be sure that
|
|
|
|
|
* the original file is closed */
|
|
|
|
|
tmpfp = NULL;
|
|
|
|
|
}
|
2016-01-07 19:01:18 +01:00
|
|
|
|
/* Static analyzer note: BAKFILENAME is never NULL here
|
|
|
|
|
because it is controlled by LASTRESNAME. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
|
2010-04-23 11:36:59 +00:00
|
|
|
|
lastresname) : 0;
|
2003-06-18 19:56:13 +00:00
|
|
|
|
xfree (tmpfilename); tmpfilename = NULL;
|
|
|
|
|
xfree (bakfilename); bakfilename = NULL;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (rc)
|
|
|
|
|
goto leave;
|
|
|
|
|
lastresname = resname;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if (noisy && !opt.quiet)
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info (_("caching keyring '%s'\n"), resname);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
rc = create_tmp_file (resname, &bakfilename, &tmpfilename, &tmpfp);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2015-01-22 16:36:28 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
rc = keyring_get_keyblock (hd, &keyblock);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (rc)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-01-22 16:36:28 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
|
|
|
|
|
continue; /* Skip legacy keys. */
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error ("keyring_get_keyblock failed: %s\n", gpg_strerror (rc));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2009-07-20 11:02:20 +00:00
|
|
|
|
if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
/* We had a few reports about corrupted keyrings; if we have
|
|
|
|
|
been called directly from the command line we delete such
|
|
|
|
|
a keyblock instead of bailing out. */
|
|
|
|
|
log_error ("unexpected keyblock found (pkttype=%d)%s\n",
|
|
|
|
|
keyblock->pkt->pkttype, noisy? " - deleted":"");
|
|
|
|
|
if (noisy)
|
|
|
|
|
continue;
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info ("Hint: backup your keys and try running '%s'\n",
|
2009-07-20 11:02:20 +00:00
|
|
|
|
"gpg --rebuild-keydb-caches");
|
|
|
|
|
rc = gpg_error (GPG_ERR_INV_KEYRING);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2014-10-31 10:29:02 +01:00
|
|
|
|
if (keyblock->pkt->pkt.public_key->version < 4)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2014-10-31 10:29:02 +01:00
|
|
|
|
/* We do not copy/cache v3 keys or any other unknown
|
|
|
|
|
packets. It is better to remove them from the keyring.
|
|
|
|
|
The code required to keep them in the keyring would be
|
|
|
|
|
too complicated. Given that we do not touch the old
|
|
|
|
|
secring.gpg a suitable backup for decryption of v3 stuff
|
2015-01-22 16:36:28 +01:00
|
|
|
|
using an older gpg version will always be available.
|
|
|
|
|
Note: This test is actually superfluous because we
|
|
|
|
|
already acted upon GPG_ERR_LEGACY_KEY. */
|
2014-10-31 10:29:02 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Check all signature to set the signature's cache flags. */
|
|
|
|
|
for (node=keyblock; node; node=node->next)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2014-10-31 10:29:02 +01:00
|
|
|
|
/* Note that this doesn't cache the result of a
|
|
|
|
|
revocation issued by a designated revoker. This is
|
|
|
|
|
because the pk in question does not carry the revkeys
|
|
|
|
|
as we haven't merged the key and selfsigs. It is
|
|
|
|
|
questionable whether this matters very much since
|
|
|
|
|
there are very very few designated revoker revocation
|
|
|
|
|
packets out there. */
|
|
|
|
|
if (node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig=node->pkt->pkt.signature;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
|
2014-10-31 10:29:02 +01:00
|
|
|
|
if(!opt.no_sig_cache && sig->flags.checked && sig->flags.valid
|
|
|
|
|
&& (openpgp_md_test_algo(sig->digest_algo)
|
|
|
|
|
|| openpgp_pk_test_algo(sig->pubkey_algo)))
|
|
|
|
|
sig->flags.checked=sig->flags.valid=0;
|
|
|
|
|
else
|
|
|
|
|
check_key_signature (keyblock, node, NULL);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
|
2014-10-31 10:29:02 +01:00
|
|
|
|
sigcount++;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2014-10-31 10:29:02 +01:00
|
|
|
|
/* Write the keyblock to the temporary file. */
|
|
|
|
|
rc = write_keyblock (tmpfp, keyblock);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto leave;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2014-10-31 10:29:02 +01:00
|
|
|
|
if ( !(++count % 50) && noisy && !opt.quiet)
|
2016-01-18 11:20:15 +01:00
|
|
|
|
log_info (ngettext("%lu keys cached so far (%lu signature)\n",
|
|
|
|
|
"%lu keys cached so far (%lu signatures)\n",
|
|
|
|
|
sigcount),
|
|
|
|
|
count, sigcount);
|
2014-10-31 10:29:02 +01:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
} /* end main loop */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (rc == -1)
|
|
|
|
|
rc = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (rc)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error ("keyring_search failed: %s\n", gpg_strerror (rc));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2016-01-18 11:20:15 +01:00
|
|
|
|
|
|
|
|
|
if (noisy || opt.verbose)
|
|
|
|
|
{
|
|
|
|
|
log_info (ngettext("%lu key cached",
|
|
|
|
|
"%lu keys cached", count), count);
|
|
|
|
|
log_printf (ngettext(" (%lu signature)\n",
|
|
|
|
|
" (%lu signatures)\n", sigcount), sigcount);
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (tmpfp)
|
|
|
|
|
{
|
|
|
|
|
if (iobuf_close (tmpfp))
|
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("error closing '%s': %s\n",
|
2003-06-05 07:14:21 +00:00
|
|
|
|
tmpfilename, strerror (errno));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
/* because we have switched resources, we can be sure that
|
|
|
|
|
* the original file is closed */
|
|
|
|
|
tmpfp = NULL;
|
|
|
|
|
}
|
|
|
|
|
rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
|
2010-04-23 11:36:59 +00:00
|
|
|
|
lastresname) : 0;
|
2003-06-18 19:56:13 +00:00
|
|
|
|
xfree (tmpfilename); tmpfilename = NULL;
|
|
|
|
|
xfree (bakfilename); bakfilename = NULL;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (tmpfp)
|
|
|
|
|
iobuf_cancel (tmpfp);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
xfree (tmpfilename);
|
|
|
|
|
xfree (bakfilename);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keyring_lock (hd, 0);
|
|
|
|
|
keyring_release (hd);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Perform insert/delete/update operation.
|
|
|
|
|
* mode 1 = insert
|
|
|
|
|
* 2 = delete
|
|
|
|
|
* 3 = update
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-23 11:36:59 +00:00
|
|
|
|
do_copy (int mode, const char *fname, KBNODE root,
|
2003-06-05 07:14:21 +00:00
|
|
|
|
off_t start_offset, unsigned int n_packets )
|
|
|
|
|
{
|
2006-04-19 11:26:11 +00:00
|
|
|
|
IOBUF fp, newfp;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
int rc=0;
|
|
|
|
|
char *bakfname = NULL;
|
|
|
|
|
char *tmpfname = NULL;
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/* Open the source file. Because we do a rename, we have to check the
|
2003-06-05 07:14:21 +00:00
|
|
|
|
permissions of the file */
|
|
|
|
|
if (access (fname, W_OK))
|
2006-09-14 16:50:33 +00:00
|
|
|
|
return gpg_error_from_syserror ();
|
2003-06-18 19:56:13 +00:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
fp = iobuf_open (fname);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (mode == 1 && !fp && errno == ENOENT) {
|
2003-06-05 07:14:21 +00:00
|
|
|
|
/* insert mode but file does not exist: create a new file */
|
|
|
|
|
KBNODE kbctx, node;
|
|
|
|
|
mode_t oldmask;
|
|
|
|
|
|
|
|
|
|
oldmask=umask(077);
|
2010-04-23 11:36:59 +00:00
|
|
|
|
if (is_secured_filename (fname)) {
|
2006-04-19 11:26:11 +00:00
|
|
|
|
newfp = NULL;
|
2010-04-01 13:24:55 +00:00
|
|
|
|
gpg_err_set_errno (EPERM);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2014-06-25 20:25:28 +02:00
|
|
|
|
newfp = iobuf_create (fname, 1);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
umask(oldmask);
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if( !newfp )
|
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error (_("can't create '%s': %s\n"), fname, strerror(errno));
|
2006-04-19 11:26:11 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if( !opt.quiet )
|
|
|
|
|
log_info(_("%s: keyring created\n"), fname );
|
|
|
|
|
|
|
|
|
|
kbctx=NULL;
|
|
|
|
|
while ( (node = walk_kbnode( root, &kbctx, 0 )) ) {
|
|
|
|
|
if( (rc = build_packet( newfp, node->pkt )) ) {
|
|
|
|
|
log_error("build_packet(%d) failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
node->pkt->pkttype, gpg_strerror (rc) );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_cancel(newfp);
|
2003-06-18 19:56:13 +00:00
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if( iobuf_close(newfp) ) {
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
log_error ("%s: close failed: %s\n", fname, strerror(errno));
|
2006-04-19 11:26:11 +00:00
|
|
|
|
return rc;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
return 0; /* ready */
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-19 11:26:11 +00:00
|
|
|
|
if( !fp )
|
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error(_("can't open '%s': %s\n"), fname, strerror(errno) );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
goto leave;
|
2006-04-19 11:26:11 +00:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2006-04-19 11:26:11 +00:00
|
|
|
|
/* Create the new file. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
|
|
|
|
|
if (rc) {
|
|
|
|
|
iobuf_close(fp);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2006-04-19 11:26:11 +00:00
|
|
|
|
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if( mode == 1 ) { /* insert */
|
|
|
|
|
/* copy everything to the new file */
|
|
|
|
|
rc = copy_all_packets (fp, newfp);
|
|
|
|
|
if( rc != -1 ) {
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error("%s: copy to '%s' failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
fname, tmpfname, gpg_strerror (rc) );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_close(fp);
|
|
|
|
|
iobuf_cancel(newfp);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( mode == 2 || mode == 3 ) { /* delete or update */
|
|
|
|
|
/* copy first part to the new file */
|
|
|
|
|
rc = copy_some_packets( fp, newfp, start_offset );
|
|
|
|
|
if( rc ) { /* should never get EOF here */
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("%s: copy to '%s' failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
fname, tmpfname, gpg_strerror (rc) );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_close(fp);
|
|
|
|
|
iobuf_cancel(newfp);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
/* skip this keyblock */
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert( n_packets );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
rc = skip_some_packets( fp, n_packets );
|
|
|
|
|
if( rc ) {
|
|
|
|
|
log_error("%s: skipping %u packets failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
fname, n_packets, gpg_strerror (rc));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_close(fp);
|
|
|
|
|
iobuf_cancel(newfp);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( mode == 1 || mode == 3 ) { /* insert or update */
|
|
|
|
|
rc = write_keyblock (newfp, root);
|
|
|
|
|
if (rc) {
|
|
|
|
|
iobuf_close(fp);
|
|
|
|
|
iobuf_cancel(newfp);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( mode == 2 || mode == 3 ) { /* delete or update */
|
|
|
|
|
/* copy the rest */
|
|
|
|
|
rc = copy_all_packets( fp, newfp );
|
|
|
|
|
if( rc != -1 ) {
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error("%s: copy to '%s' failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
fname, tmpfname, gpg_strerror (rc) );
|
2003-06-05 07:14:21 +00:00
|
|
|
|
iobuf_close(fp);
|
|
|
|
|
iobuf_cancel(newfp);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* close both files */
|
|
|
|
|
if( iobuf_close(fp) ) {
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
log_error("%s: close failed: %s\n", fname, strerror(errno) );
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
if( iobuf_close(newfp) ) {
|
2006-09-14 16:50:33 +00:00
|
|
|
|
rc = gpg_error_from_syserror ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
|
rc = rename_tmp_file (bakfname, tmpfname, fname);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
leave:
|
2006-04-19 11:26:11 +00:00
|
|
|
|
xfree(bakfname);
|
|
|
|
|
xfree(tmpfname);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|