X-Git-Url: http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blobdiff_plain;f=g10%2Fkeyring.c;h=d069b139788ffb0524ad2eadb25f4adc2c1c2b64;hp=56acaa3ead00f856c86aa03b121a861ae270ea15;hb=d9e2dcc1a9182b3144fa4f9b23b6ce7fb2cf63cc;hpb=03d3322e5fb928d48ea4192fd2f2cc851d791421
diff --git a/g10/keyring.c b/g10/keyring.c
index 56acaa3ea..d069b1397 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -1,11 +1,11 @@
/* keyring.c - keyring file handling
- * Copyright (C) 2001, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2004, 2009, 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
@@ -14,9 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see .
*/
#include
@@ -52,10 +50,11 @@ typedef struct off_item **OffsetHashTable;
typedef struct keyring_name *KR_NAME;
-struct keyring_name {
+struct keyring_name
+{
struct keyring_name *next;
- int secret;
- DOTLOCK lockhd;
+ int read_only;
+ dotlock_t lockhd;
int is_locked;
int did_full_scan;
char fname[1];
@@ -69,9 +68,9 @@ static OffsetHashTable kr_offtbl;
static int kr_offtbl_ready;
-struct keyring_handle {
+struct keyring_handle
+{
CONST_KR_NAME resource;
- int secret; /* this is for a secret keyring */
struct {
CONST_KR_NAME kr;
IOBUF iobuf;
@@ -93,7 +92,7 @@ struct keyring_handle {
-static int do_copy (int mode, const char *fname, KBNODE root, int secret,
+static int do_copy (int mode, const char *fname, KBNODE root,
off_t start_offset, unsigned int n_packets );
@@ -160,6 +159,8 @@ update_offset_hash_table (OffsetHashTable tbl, u32 *kid, off_t off)
{
struct off_item *k;
+ (void)off;
+
for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
{
if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
@@ -199,7 +200,7 @@ update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
* if a new keyring was registered.
*/
int
-keyring_register_filename (const char *fname, int secret, void **ptr)
+keyring_register_filename (const char *fname, int read_only, void **ptr)
{
KR_NAME kr;
@@ -208,19 +209,19 @@ keyring_register_filename (const char *fname, int secret, void **ptr)
for (kr=kr_names; kr; kr = kr->next)
{
- if ( !compare_filenames (kr->fname, fname) )
+ if (same_file_p (kr->fname, fname))
{
+ /* Already registered. */
+ if (read_only)
+ kr->read_only = 1;
*ptr=kr;
- return 0; /* already registered */
+ return 0;
}
}
- if (secret)
- register_secured_file (fname);
-
kr = xmalloc (sizeof *kr + strlen (fname));
strcpy (kr->fname, fname);
- kr->secret = !!secret;
+ kr->read_only = read_only;
kr->lockhd = NULL;
kr->is_locked = 0;
kr->did_full_scan = 0;
@@ -242,26 +243,24 @@ keyring_is_writable (void *token)
{
KR_NAME r = token;
- return r? !access (r->fname, W_OK) : 0;
+ return r? (r->read_only || !access (r->fname, W_OK)) : 0;
}
-/* Create a new handle for the resource associated with TOKEN. SECRET
- is just just as a cross-check.
+/* Create a new handle for the resource associated with TOKEN.
The returned handle must be released using keyring_release (). */
KEYRING_HANDLE
-keyring_new (void *token, int secret)
+keyring_new (void *token)
{
KEYRING_HANDLE hd;
KR_NAME resource = token;
- assert (resource && !resource->secret == !secret);
+ assert (resource);
hd = xmalloc_clear (sizeof *hd);
hd->resource = resource;
- hd->secret = !!secret;
active_handles++;
return hd;
}
@@ -290,7 +289,7 @@ keyring_get_resource_name (KEYRING_HANDLE hd)
/*
- * Lock the keyring with the given handle, or unlok if yes is false.
+ * Lock the keyring with the given handle, or unlock if YES is false.
* We ignore the handle and lock all registered files.
*/
int
@@ -299,6 +298,8 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
KR_NAME kr;
int rc = 0;
+ (void)hd;
+
if (yes) {
/* first make sure the lock handles are created */
for (kr=kr_names; kr; kr = kr->next) {
@@ -417,42 +418,52 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
}
in_cert = 1;
- if (pkt->pkttype == PKT_RING_TRUST) {
+ if (pkt->pkttype == PKT_RING_TRUST)
+ {
/*(this code is duplicated after the loop)*/
if ( lastnode
&& lastnode->pkt->pkttype == PKT_SIGNATURE
&& (pkt->pkt.ring_trust->sigcache & 1) ) {
- /* this is a ring trust packet with a checked signature
+ /* This is a ring trust packet with a checked signature
* status cache following directly a signature paket.
- * Set the cache status into that signature packet */
+ * Set the cache status into that signature packet. */
PKT_signature *sig = lastnode->pkt->pkt.signature;
sig->flags.checked = 1;
sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
}
- /* reset lastnode, so that we set the cache status only from
- * the ring trust packet immediately folling a signature */
+ /* Reset LASTNODE, so that we set the cache status only from
+ * the ring trust packet immediately following a signature. */
lastnode = NULL;
- }
- else {
- node = lastnode = new_kbnode (pkt);
- if (!keyblock)
- keyblock = node;
- else
- add_kbnode (keyblock, node);
-
- if ( pkt->pkttype == PKT_PUBLIC_KEY
- || pkt->pkttype == PKT_PUBLIC_SUBKEY
- || pkt->pkttype == PKT_SECRET_KEY
- || pkt->pkttype == PKT_SECRET_SUBKEY) {
- if (++pk_no == hd->found.pk_no)
- node->flag |= 1;
- }
- else if ( pkt->pkttype == PKT_USER_ID) {
- if (++uid_no == hd->found.uid_no)
- node->flag |= 2;
- }
- }
+ 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;
+
+ default:
+ break;
+ }
pkt = xmalloc (sizeof *pkt);
init_packet(pkt);
@@ -497,6 +508,9 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
if (!hd->found.kr)
return -1; /* no successful prior search */
+ if (hd->found.kr->read_only)
+ return gpg_error (GPG_ERR_EACCES);
+
if (!hd->found.n_packets) {
/* need to know the number of packets - do a dummy get_keyblock*/
rc = keyring_get_keyblock (hd, NULL);
@@ -515,10 +529,10 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
hd->current.iobuf = NULL;
/* do the update */
- rc = do_copy (3, hd->found.kr->fname, kb, hd->secret,
+ rc = do_copy (3, hd->found.kr->fname, kb,
hd->found.offset, hd->found.n_packets );
if (!rc) {
- if (!hd->secret && kr_offtbl)
+ if (kr_offtbl)
{
update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
}
@@ -538,16 +552,24 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
if (!hd)
fname = NULL;
else if (hd->found.kr)
+ {
fname = hd->found.kr->fname;
+ if (hd->found.kr->read_only)
+ return gpg_error (GPG_ERR_EACCES);
+ }
else if (hd->current.kr)
+ {
fname = hd->current.kr->fname;
+ if (hd->current.kr->read_only)
+ return gpg_error (GPG_ERR_EACCES);
+ }
else
fname = hd->resource? hd->resource->fname:NULL;
if (!fname)
return G10ERR_GENERAL;
- /* close this one otherwise we will lose the position for
+ /* 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.
*/
@@ -555,8 +577,8 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
hd->current.iobuf = NULL;
/* do the insert */
- rc = do_copy (1, fname, kb, hd->secret, 0, 0 );
- if (!rc && !hd->secret && kr_offtbl)
+ rc = do_copy (1, fname, kb, 0, 0 );
+ if (!rc && kr_offtbl)
{
update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
}
@@ -573,6 +595,9 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
if (!hd->found.kr)
return -1; /* no successful prior search */
+ if (hd->found.kr->read_only)
+ return gpg_error (GPG_ERR_EACCES);
+
if (!hd->found.n_packets) {
/* need to know the number of packets - do a dummy get_keyblock*/
rc = keyring_get_keyblock (hd, NULL);
@@ -592,7 +617,7 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
hd->current.iobuf = NULL;
/* do the delete */
- rc = do_copy (2, hd->found.kr->fname, NULL, hd->secret,
+ rc = do_copy (2, hd->found.kr->fname, NULL,
hd->found.offset, hd->found.n_packets );
if (!rc) {
/* better reset the found info */
@@ -874,7 +899,6 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
int use_offtbl;
PKT_user_id *uid = NULL;
PKT_public_key *pk = NULL;
- PKT_secret_key *sk = NULL;
u32 aki[2];
/* figure out what information we need */
@@ -920,7 +944,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
if (rc)
return rc;
- use_offtbl = !hd->secret && kr_offtbl;
+ use_offtbl = !!kr_offtbl;
if (!use_offtbl)
;
else if (!kr_offtbl_ready)
@@ -964,7 +988,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
hd->word_match.name = xstrdup (name);
hd->word_match.pattern = prepare_word_match (name);
}
- name = hd->word_match.pattern;
+ /* name = hd->word_match.pattern; */
}
init_packet(&pkt);
@@ -992,10 +1016,11 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
}
pk = NULL;
- sk = NULL;
uid = NULL;
if ( pkt.pkttype == PKT_PUBLIC_KEY
- || pkt.pkttype == PKT_PUBLIC_SUBKEY)
+ || pkt.pkttype == PKT_PUBLIC_SUBKEY
+ || pkt.pkttype == PKT_SECRET_KEY
+ || pkt.pkttype == PKT_SECRET_SUBKEY)
{
pk = pkt.pkt.public_key;
++pk_no;
@@ -1016,21 +1041,6 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
uid = pkt.pkt.user_id;
++uid_no;
}
- else if ( pkt.pkttype == PKT_SECRET_KEY
- || pkt.pkttype == PKT_SECRET_SUBKEY)
- {
- sk = pkt.pkt.secret_key;
- ++pk_no;
-
- if (need_fpr) {
- fingerprint_from_sk (sk, afp, &an);
- while (an < 20) /* fill up to 20 bytes */
- afp[an++] = 0;
- }
- if (need_keyid)
- keyid_from_sk (sk, aki);
-
- }
for (n=0; n < ndesc; n++)
{
@@ -1051,29 +1061,29 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
break;
case KEYDB_SEARCH_MODE_SHORT_KID:
- if ((pk||sk) && desc[n].u.kid[1] == aki[1])
+ if (pk && desc[n].u.kid[1] == aki[1])
goto found;
break;
case KEYDB_SEARCH_MODE_LONG_KID:
- if ((pk||sk) && desc[n].u.kid[0] == aki[0]
+ if (pk && desc[n].u.kid[0] == aki[0]
&& desc[n].u.kid[1] == aki[1])
goto found;
break;
case KEYDB_SEARCH_MODE_FPR16:
- if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 16))
+ if (pk && !memcmp (desc[n].u.fpr, afp, 16))
goto found;
break;
case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
- if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20))
+ if (pk && !memcmp (desc[n].u.fpr, afp, 20))
goto found;
break;
case KEYDB_SEARCH_MODE_FIRST:
- if (pk||sk)
+ if (pk)
goto found;
break;
case KEYDB_SEARCH_MODE_NEXT:
- if (pk||sk)
+ if (pk)
goto found;
break;
default:
@@ -1103,7 +1113,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
{
hd->found.offset = main_offset;
hd->found.kr = hd->current.kr;
- hd->found.pk_no = (pk||sk)? pk_no : 0;
+ hd->found.pk_no = pk? pk_no : 0;
hd->found.uid_no = uid? uid_no : 0;
}
else if (rc == -1)
@@ -1115,11 +1125,10 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
{
KR_NAME kr;
- /* First set the did_full_scan flag for this keyring (ignore
- secret keyrings) */
+ /* First set the did_full_scan flag for this keyring. */
for (kr=kr_names; kr; kr = kr->next)
{
- if (!kr->secret && hd->resource == kr)
+ if (hd->resource == kr)
{
kr->did_full_scan = 1;
break;
@@ -1129,7 +1138,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
offtbl ready */
for (kr=kr_names; kr; kr = kr->next)
{
- if (!kr->secret && !kr->did_full_scan)
+ if (!kr->did_full_scan)
break;
}
if (!kr)
@@ -1193,7 +1202,7 @@ create_tmp_file (const char *template,
if (is_secured_filename (tmpfname))
{
*r_fp = NULL;
- errno = EPERM;
+ gpg_err_set_errno (EPERM);
}
else
*r_fp = iobuf_create (tmpfname);
@@ -1214,52 +1223,42 @@ create_tmp_file (const char *template,
static int
-rename_tmp_file (const char *bakfname, const char *tmpfname,
- const char *fname, int secret )
+rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
{
- int rc=0;
+ int rc = 0;
- /* invalidate close caches*/
- iobuf_ioctl (NULL, 2, 0, (char*)tmpfname );
- iobuf_ioctl (NULL, 2, 0, (char*)bakfname );
- iobuf_ioctl (NULL, 2, 0, (char*)fname );
+ /* Invalidate close caches. */
+ if (iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ))
+ {
+ rc = gpg_error_from_syserror ();
+ goto fail;
+ }
+ iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname );
+ iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname );
- /* first make a backup file except for secret keyrings */
- if (!secret)
- {
+ /* First make a backup file. */
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
- remove (bakfname);
+ gnupg_remove (bakfname);
#endif
- if (rename (fname, bakfname) )
- {
- rc = gpg_error_from_syserror ();
- log_error ("renaming `%s' to `%s' failed: %s\n",
- fname, bakfname, strerror(errno) );
- return rc;
- }
+ if (rename (fname, bakfname) )
+ {
+ rc = gpg_error_from_syserror ();
+ log_error ("renaming `%s' to `%s' failed: %s\n",
+ fname, bakfname, strerror(errno) );
+ return rc;
}
/* then rename the file */
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
- remove( fname );
+ gnupg_remove( fname );
#endif
- if (secret)
- unregister_secured_file (fname);
if (rename (tmpfname, fname) )
{
rc = gpg_error_from_syserror ();
log_error (_("renaming `%s' to `%s' failed: %s\n"),
tmpfname, fname, strerror(errno) );
register_secured_file (fname);
- if (secret)
- {
- log_info(_("WARNING: 2 files with confidential"
- " information exists.\n"));
- log_info(_("%s is the unchanged one\n"), fname );
- log_info(_("%s is the new one\n"), tmpfname );
- log_info(_("Please fix this possible security flaw\n"));
- }
- return rc;
+ goto fail;
}
/* Now make sure the file has the same permissions as the original */
@@ -1270,17 +1269,18 @@ rename_tmp_file (const char *bakfname, const char *tmpfname,
statbuf.st_mode=S_IRUSR | S_IWUSR;
- if(((secret && !opt.preserve_permissions) ||
- (stat(bakfname,&statbuf)==0)) &&
- (chmod(fname,statbuf.st_mode)==0))
+ if (!stat (bakfname, &statbuf) && !chmod (fname, statbuf.st_mode))
;
else
- log_error("WARNING: unable to restore permissions to `%s': %s",
- fname,strerror(errno));
+ log_error ("WARNING: unable to restore permissions to `%s': %s",
+ fname, strerror(errno));
}
#endif
return 0;
+
+ fail:
+ return rc;
}
@@ -1344,7 +1344,7 @@ keyring_rebuild_cache (void *token,int noisy)
int rc;
ulong count = 0, sigcount = 0;
- hd = keyring_new (token, 0);
+ hd = keyring_new (token);
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_FIRST;
@@ -1372,7 +1372,7 @@ keyring_rebuild_cache (void *token,int noisy)
tmpfp = NULL;
}
rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
- lastresname, 0) : 0;
+ lastresname) : 0;
xfree (tmpfilename); tmpfilename = NULL;
xfree (bakfilename); bakfilename = NULL;
if (rc)
@@ -1392,7 +1392,20 @@ keyring_rebuild_cache (void *token,int noisy)
log_error ("keyring_get_keyblock failed: %s\n", g10_errstr(rc));
goto leave;
}
- assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+ 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;
+ log_info ("Hint: backup your keys and try running `%s'\n",
+ "gpg --rebuild-keydb-caches");
+ rc = gpg_error (GPG_ERR_INV_KEYRING);
+ goto leave;
+ }
/* check all signature to set the signature's cache flags */
for (node=keyblock; node; node=node->next)
@@ -1452,7 +1465,7 @@ keyring_rebuild_cache (void *token,int noisy)
tmpfp = NULL;
}
rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
- lastresname, 0) : 0;
+ lastresname) : 0;
xfree (tmpfilename); tmpfilename = NULL;
xfree (bakfilename); bakfilename = NULL;
@@ -1475,7 +1488,7 @@ keyring_rebuild_cache (void *token,int noisy)
* 3 = update
*/
static int
-do_copy (int mode, const char *fname, KBNODE root, int secret,
+do_copy (int mode, const char *fname, KBNODE root,
off_t start_offset, unsigned int n_packets )
{
IOBUF fp, newfp;
@@ -1495,9 +1508,9 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
mode_t oldmask;
oldmask=umask(077);
- if (!secret && is_secured_filename (fname)) {
+ if (is_secured_filename (fname)) {
newfp = NULL;
- errno = EPERM;
+ gpg_err_set_errno (EPERM);
}
else
newfp = iobuf_create (fname);
@@ -1541,8 +1554,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
iobuf_close(fp);
goto leave;
}
- if (secret)
- register_secured_file (tmpfname);
if( mode == 1 ) { /* insert */
/* copy everything to the new file */
@@ -1551,8 +1562,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
log_error("%s: copy to `%s' failed: %s\n",
fname, tmpfname, g10_errstr(rc) );
iobuf_close(fp);
- if (secret)
- unregister_secured_file (tmpfname);
iobuf_cancel(newfp);
goto leave;
}
@@ -1566,8 +1575,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
log_error ("%s: copy to `%s' failed: %s\n",
fname, tmpfname, g10_errstr(rc) );
iobuf_close(fp);
- if (secret)
- unregister_secured_file (tmpfname);
iobuf_cancel(newfp);
goto leave;
}
@@ -1578,8 +1585,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
log_error("%s: skipping %u packets failed: %s\n",
fname, n_packets, g10_errstr(rc));
iobuf_close(fp);
- if (secret)
- unregister_secured_file (tmpfname);
iobuf_cancel(newfp);
goto leave;
}
@@ -1589,8 +1594,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
rc = write_keyblock (newfp, root);
if (rc) {
iobuf_close(fp);
- if (secret)
- unregister_secured_file (tmpfname);
iobuf_cancel(newfp);
goto leave;
}
@@ -1603,8 +1606,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
log_error("%s: copy to `%s' failed: %s\n",
fname, tmpfname, g10_errstr(rc) );
iobuf_close(fp);
- if (secret)
- unregister_secured_file (tmpfname);
iobuf_cancel(newfp);
goto leave;
}
@@ -1623,7 +1624,7 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
goto leave;
}
- rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
+ rc = rename_tmp_file (bakfname, tmpfname, fname);
leave:
xfree(bakfname);