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);