aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2001-09-24 16:03:14 +0000
committerWerner Koch <[email protected]>2001-09-24 16:03:14 +0000
commita3af543617515c0bb35b54d456d8c6a5f463dc21 (patch)
tree33b065ae6557a633832e5a98df18a3730103c78e
parentCode cleanups (diff)
downloadgnupg-a3af543617515c0bb35b54d456d8c6a5f463dc21.tar.gz
gnupg-a3af543617515c0bb35b54d456d8c6a5f463dc21.zip
Revamped the trustDB
-rw-r--r--TODO11
-rw-r--r--doc/ChangeLog4
-rw-r--r--doc/DETAILS2
-rw-r--r--doc/gpg.sgml40
-rw-r--r--g10/ChangeLog27
-rw-r--r--g10/g10.c16
-rw-r--r--g10/getkey.c38
-rw-r--r--g10/gpgv.c11
-rw-r--r--g10/helptext.c9
-rw-r--r--g10/import.c33
-rw-r--r--g10/keydb.h3
-rw-r--r--g10/keyedit.c55
-rw-r--r--g10/keygen.c15
-rw-r--r--g10/keylist.c6
-rw-r--r--g10/keyring.c27
-rw-r--r--g10/keyring.obin57000 -> 57216 bytes
-rw-r--r--g10/mainproc.c6
-rw-r--r--g10/options.h1
-rw-r--r--g10/pkclist.c310
-rw-r--r--g10/tdbdump.c392
-rw-r--r--g10/tdbio.c771
-rw-r--r--g10/tdbio.h133
-rw-r--r--g10/trustdb.c3344
-rw-r--r--g10/trustdb.h38
24 files changed, 1609 insertions, 3683 deletions
diff --git a/TODO b/TODO
index ddac982de..046267c7f 100644
--- a/TODO
+++ b/TODO
@@ -17,9 +17,6 @@
* Check that no secret temporary results are stored in the result parameter
of the mpi functions. We have already done this for mpi-mul.c
- * check whether we can remove all the expire stuff in trustdb because this
- is now done in getkey.
-
* We need another special packet at the end of a clearsign message to mark
it's end and allow for multiple signature for one message. And
add a real grammar to the code in mainproc.c
@@ -35,16 +32,8 @@
* add some minor things vor VMS.
- * Don't get the ultimately trusted keys from the secring but store
- it permanently in the trustdb. This way we don't need a secring at all.
- [ currently solved by re-introducing --trusted-key ] Eventually we
- will have commands --{add,remove}-trusted-key which keeps them in
- special trustdb records.
-
* Use DSA keys with the test suite (partly done)
- * g10/trustdb.c (make_sig_records): fix the fixme.
-
* Fix the bug in the mips assembler code
* Add a way to show the fingerprint of an key signator's keys
diff --git a/doc/ChangeLog b/doc/ChangeLog
index d9ef0eaf8..5e6dea587 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,7 @@
+2001-09-24 Werner Koch <[email protected]>
+
+ * gpg.sgml: Described --{update,check}-trustdb.
+
2001-09-03 Werner Koch <[email protected]>
* gpg.sgml, gpgv.sgml: Removed GDBM stuff.
diff --git a/doc/DETAILS b/doc/DETAILS
index 8d2217844..66563663b 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -469,7 +469,7 @@ the DB is always of type 1 and this is the only record of this type.
1 u32 record number of shadow directory hash table
It does not make sense to combine this table with the key table
because the keyid is not in every case a part of the fingerprint.
- 4 bytes reserved for version extension record
+ 1 u32 record number of the trusthashtbale
Record type 2: (directory record)
diff --git a/doc/gpg.sgml b/doc/gpg.sgml
index f27249971..717f7e394 100644
--- a/doc/gpg.sgml
+++ b/doc/gpg.sgml
@@ -505,7 +505,7 @@ not be expected to successfully import such a key.
<listitem><para>
Import/merge keys. This adds the given keys to the
keyring.
-The fast version does not build
+The fast version does not update
the trustdb; this can be done at any time with the
command --update-trustdb.
</para>
@@ -527,10 +527,34 @@ give the name of this keyserver.
<varlistentry>
-<term>--export-ownertrust</term>
+<term>--recv-keys &ParmKeyIDs;</term>
<listitem><para>
-List the assigned ownertrust values in ASCII format
-for backup purposes.
+Import the keys with the given key IDs from a HKP
+keyserver. Option --keyserver must be used to
+give the name of this keyserver.
+</para></listitem></varlistentry>
+
+<varlistentry>
+<term>--update-trustdb</term>
+<listitem><para>
+Do trust DB maintenance. This command goes over all keys and builds
+the Web-of-Trust. This is an intercative command because it may has to
+ask for the "ownertrust" values of keys. The user has to give an
+estimation in how far she trusts the owner of the displayed key to
+correctly certify (sign) other keys. It does only ask for that value
+if it has not yet been assigned to a key. Using the edit menu, that
+value can be changed at any time later.
+</para></listitem></varlistentry>
+
+<varlistentry>
+<term>--check-trustdb</term>
+<listitem><para>
+Do trust DB maintenance without user interaction. Form time to time
+the trust database must be updated so that expired keys and resulting
+changes in the Web-of_trust can be tracked. GnuPG tries to figure
+when this is required and then does it implicitly; this command can be
+used to force such a check. The processing is identically to that of
+--update-trustdb but it skips keys with a not yet defined "ownertrust".
</para></listitem></varlistentry>
@@ -1164,6 +1188,14 @@ However, due to the fact that the signature creation needs manual
interaction, this performance penalty does not matter in most settings.
</para></listitem></varlistentry>
+<term>--no-auto-check-trustdb</term>
+<listitem><para>
+If GnuPG feels that its information about the Web-of-Trust has to be
+updated, it automatically runs the --check-trustdb command
+internally. As this is a time consuming process, this option allow to
+disable the automatic invocation.
+</para></listitem></varlistentry>
+
<varlistentry>
<term>--throw-keyid</term>
<listitem><para>
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 47df95b87..96ef0c6fa 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,4 +1,29 @@
-2001-09-20 Werner Koch <[email protected]>
+2001-09-24 Werner Koch <[email protected]>
+
+ * g10.c, options.h: New option --no-auto-check-trustdb.
+
+ * keygen.c (do_generate_keypair): Set newly created keys to
+ ultimately trusted.
+
+ * tdbio.h, tdbio.c: Removed all support for records DIR, KEY, UID,
+ PREF, SIG, SDIR and CACH. Changed migration function to work
+ direct on the file.
+ (tdbio_read_nextcheck): New.
+ (tdbio_write_nextcheck): New.
+
+2001-09-21 Werner Koch <[email protected]>
+
+ Revamped the entire key validation system.
+ * trustdb.c: Complete rewrite. No more validation on demand,
+ removed some functions, adjusted to all callers to use the new
+ and much simpler interface. Does not use the LID anymore.
+ * tdbio.c, tdbio.h: Add new record types trust and valid. Wrote a
+ migration function to convert to the new trustdb layout.
+ * getkey.c (classify_user_id2): Do not allow the use of the "#"
+ prefix.
+ * keydb.h: Removed the TDBIDX mode add a skipfnc to the
+ descriptor.
+ * keyring.c (keyring_search): Implemented skipfnc.
* passphrase.c (agent_open): Add missing bracket. Include windows.h.
diff --git a/g10/g10.c b/g10/g10.c
index 6c92f5675..04b73e163 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -224,6 +224,7 @@ enum cmd_and_opt_values { aNull = 0,
oFixedListMode,
oNoSigCache,
oNoSigCreateCheck,
+ oNoAutoCheckTrustDB,
oPreservePermissions,
oPreferenceList,
oEmu3DESS2KBug, /* will be removed in 1.1 */
@@ -276,7 +277,7 @@ static ARGPARSE_OPTS opts[] = {
{ aUpdateTrustDB,
"update-trustdb",0 , N_("update the trust database")},
{ aCheckTrustDB,
- "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
+ "check-trustdb",0 , N_("unattended trust database update")},
{ aFixTrustDB, "fix-trustdb",0 , N_("fix a corrupted trust database")},
{ aDeArmor, "dearmor", 256, N_("De-Armor a file or stdin") },
{ aDeArmor, "dearmour", 256, "@" },
@@ -433,6 +434,7 @@ static ARGPARSE_OPTS opts[] = {
{ oNoAutoKeyRetrieve, "no-auto-key-retrieve", 0, "@" },
{ oNoSigCache, "no-sig-cache", 0, "@" },
{ oNoSigCreateCheck, "no-sig-create-check", 0, "@" },
+ { oNoAutoCheckTrustDB, "no-auto-check-trustdb", 0, "@"},
{ oMergeOnly, "merge-only", 0, "@" },
{ oAllowSecretKeyImport, "allow-secret-key-import", 0, "@" },
{ oTryAllSecrets, "try-all-secrets", 0, "@" },
@@ -1083,6 +1085,7 @@ main( int argc, char **argv )
iobuf_enable_special_filenames (1);
break;
case oNoExpensiveTrustChecks: opt.no_expensive_trust_checks=1; break;
+ case oNoAutoCheckTrustDB: opt.no_auto_check_trustdb=1; break;
case oPreservePermissions: opt.preserve_permissions=1; break;
case oPreferenceList: preference_list = pargs.r.ret_str; break;
default : pargs.err = configfp? 1:2; break;
@@ -1648,15 +1651,8 @@ main( int argc, char **argv )
break;
case aCheckTrustDB:
- if( !argc )
- check_trustdb(NULL);
- else {
- for( ; argc; argc--, argv++ ) {
- username = make_username( *argv );
- check_trustdb( username );
- m_free(username);
- }
- }
+ /* Old versions allowed for arguments - ignore them */
+ check_trustdb();
break;
case aFixTrustDB:
diff --git a/g10/getkey.c b/g10/getkey.c
index 2faa27cc5..d18d3440f 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -528,6 +528,7 @@ hextobyte( const byte *s )
/****************
* Return the type of the user id:
*
+ * Please use the constants KEYDB_SERCH_MODE_xxx
* 0 = Invalid user ID
* 1 = exact match
* 2 = match a substring
@@ -625,11 +626,7 @@ classify_user_id2( const char *name,
break;
case '#': /* local user id */
- mode = KEYDB_SEARCH_MODE_TDBIDX;
- s++;
- if (keyid_from_lid(strtoul(s, NULL, 10), desc->u.kid))
- desc->u.kid[0] = desc->u.kid[1] = 0;
- break;
+ return 0; /* This is now obsolete and van't not be used anymore*/
case ':': /*Unified fingerprint */
{
@@ -955,37 +952,6 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
}
-
-/****************
- * Search for a key with the given lid and return the entire keyblock
- */
-int
-get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
-{
- int rc;
- struct getkey_ctx_s ctx;
- u32 kid[2];
-
- if( keyid_from_lid( lid, kid ) )
- kid[0] = kid[1] = 0;
- memset( &ctx, 0, sizeof ctx );
- ctx.exact = 1;
- ctx.not_allocated = 1;
- ctx.kr_handle = keydb_new (0);
- ctx.nitems = 1;
- ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
- ctx.items[0].u.kid[0] = kid[0];
- ctx.items[0].u.kid[1] = kid[1];
- rc = lookup( &ctx, ret_keyblock, 0 );
- get_pubkey_end( &ctx );
-
- return rc;
-}
-
-
-
-
-
/****************
* Get a secret key by name and store it into sk
* If NAME is NULL use the default key
diff --git a/g10/gpgv.c b/g10/gpgv.c
index e64b7576e..d80cbd51f 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -229,21 +229,14 @@ check_signatures_trust( PKT_signature *sig )
* instead
*/
int
-keyid_from_lid( ulong lid, u32 *keyid )
-{
- return G10ERR_TRUSTDB;
-}
-
-/* Stub: */
-int
-query_trust_info( PKT_public_key *pk, const byte *namehash )
+get_validity_info (PKT_public_key *pk, const byte *namehash )
{
return '?';
}
/* Stub: */
int
-get_ownertrust_info( ulong lid )
+get_ownertrust_info (PKT_public_key *pk)
{
return '?';
}
diff --git a/g10/helptext.c b/g10/helptext.c
index 35feccc71..77497b6ce 100644
--- a/g10/helptext.c
+++ b/g10/helptext.c
@@ -203,11 +203,18 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = {
"self-signatures fill be advanced by one second.\n"
)},
+{ "keyedit.trust.set_ultimate.okay", N_(
+ "To build the Web-of-Trust, GnuPG needs to know which keys are\n"
+ "ultimately trusted - those are usually the keys for which you have\n"
+ "access to the secret key. Answer \"yes\" to set this key to\n"
+ "ultimately trusted; if you choose not to do so, you will then be\n"
+ "taken to the regular ownertrust menu.\n"
+)},
+
{ "passphrase.enter", N_(
""
"Please enter the passhrase; this is a secret sentence \n"
-" Blurb, blurb,.... "
)},
diff --git a/g10/import.c b/g10/import.c
index ad9def008..dc17505ef 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -158,8 +158,7 @@ import_keys( char **fnames, int nnames, int fast, void *stats_handle )
import_print_stats (stats);
import_release_stats_handle (stats);
}
- if( !fast )
- sync_trustdb();
+
}
int
@@ -177,8 +176,7 @@ import_keys_stream( IOBUF inp, int fast, void *stats_handle )
import_print_stats (stats);
import_release_stats_handle (stats);
}
- if( !fast )
- sync_trustdb();
+
return rc;
}
@@ -591,21 +589,8 @@ import_one( const char *fname, KBNODE keyblock, int fast,
}
keydb_release (hd); hd = NULL;
}
- if( !rc && !fast ) {
- rc = query_trust_record( new_key? pk : pk_orig );
- if( rc && rc != -1 )
- log_error("trustdb error: %s\n", g10_errstr(rc) );
- else if( rc == -1 ) { /* not found trustdb */
- rc = insert_trust_record( new_key? keyblock : keyblock_orig );
- if( rc )
- log_error("key %08lX: trustdb insert failed: %s\n",
- (ulong)keyid[1], g10_errstr(rc) );
- }
- else if( mod_key )
- rc = update_trust_record( keyblock_orig, 1, NULL );
- else
- rc = clear_trust_checked_flag( new_key? pk : pk_orig );
- }
+ if (!rc)
+ revalidation_mark ();
leave:
release_kbnode( keyblock_orig );
@@ -793,15 +778,7 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
log_info( _("key %08lX: revocation certificate imported\n"),
(ulong)keyid[1]);
stats->n_revoc++;
- if( clear_trust_checked_flag( pk ) ) {
- /* seems that we have to insert the record first */
- rc = insert_trust_record( keyblock );
- if( rc )
- log_error("key %08lX: trustdb insert failed: %s\n",
- (ulong)keyid[1], g10_errstr(rc) );
- else
- rc = clear_trust_checked_flag( pk );
- }
+ revalidation_mark ();
leave:
keydb_release (hd);
diff --git a/g10/keydb.h b/g10/keydb.h
index 63149b28c..67a9e10f2 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -120,7 +120,6 @@ typedef enum {
KEYDB_SEARCH_MODE_WORDS,
KEYDB_SEARCH_MODE_SHORT_KID,
KEYDB_SEARCH_MODE_LONG_KID,
- KEYDB_SEARCH_MODE_TDBIDX,
KEYDB_SEARCH_MODE_FPR16,
KEYDB_SEARCH_MODE_FPR20,
KEYDB_SEARCH_MODE_FPR,
@@ -130,6 +129,8 @@ typedef enum {
struct keydb_search_desc {
KeydbSearchMode mode;
+ int (*skipfnc)(void *,u32*);
+ void *skipfncvalue;
union {
const char *name;
char fpr[MAX_FINGERPRINT_LEN];
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 9656385a6..2e66b4b6e 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -373,7 +373,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
}
} /* end loop over signators */
if( upd_trust && primary_pk ) {
- rc = clear_trust_checked_flag( primary_pk );
+ revalidation_mark ();
}
@@ -793,11 +793,6 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
if( !sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN )
&& sign_mode )
goto do_cmd_save;
- /* Actually we should do a update_trust_record() here so that
- * the trust gets displayed correctly. however this is not possible
- * because we would have to save the keyblock first - something
- * we don't want to do without an explicit save command.
- */
break;
case cmdDEBUG:
@@ -933,11 +928,22 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
case cmdTRUST:
show_key_with_all_names( keyblock, 0, 0, 1, 0 );
tty_printf("\n");
+ if ( sec_keyblock
+ && cpr_get_answer_is_yes(
+ "keyedit.trust.set_ultimate.okay",
+ _("Do you want to set this key to ultimately trusted? "))) {
+ PKT_public_key *pk = keyblock->pkt->pkt.public_key;
+
+ update_ownertrust (pk,
+ ((get_ownertrust (pk) & ~TRUST_MASK)
+ | TRUST_ULTIMATE ));
+ redisplay = 1;
+ break;
+ }
+
if( edit_ownertrust( find_kbnode( keyblock,
- PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
+ PKT_PUBLIC_KEY )->pkt->pkt.public_key, 1 ) )
redisplay = 1;
- /* we don't need to set modified here, as the trustvalues
- * are updated immediately */
break;
case cmdPREF:
@@ -1028,13 +1034,8 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
/* TODO: we should keep track whether we have changed
* something relevant to the trustdb */
- if( !modified && sign_mode )
- rc = 0; /* we can skip at least in this case */
- else
- rc = update_trust_record( keyblock, 0, NULL );
- if( rc )
- log_error(_("update of trustdb failed: %s\n"),
- g10_errstr(rc) );
+ if( !(!modified && sign_mode) )
+ revalidation_mark ();
goto leave;
case cmdINVCMD:
@@ -1143,8 +1144,9 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
/* do it here, so that debug messages don't clutter the
* output */
- trust = query_trust_info(pk, NULL);
- otrust = get_ownertrust_info( pk->local_id );
+
+ trust = get_validity_info (pk, NULL);
+ otrust = get_ownertrust_info (pk);
}
tty_printf(_("%s%c %4u%c/%08lX created: %s expires: %s"),
@@ -1158,7 +1160,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
tty_printf(_(" trust: %c/%c"), otrust, trust );
if( node->pkt->pkttype == PKT_PUBLIC_KEY
- && (get_ownertrust( pk->local_id )&TRUST_FLAG_DISABLED)) {
+ && (get_ownertrust (pk)&TRUST_FLAG_DISABLED)) {
tty_printf("\n*** ");
tty_printf(_("This key has been disabled"));
}
@@ -2127,7 +2129,7 @@ menu_revsig( KBNODE keyblock )
}
if( upd_trust )
- clear_trust_checked_flag( primary_pk );
+ revalidation_mark ();
release_revocation_reason_info( reason );
return changed;
}
@@ -2192,7 +2194,7 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
/*commit_kbnode( &sec_keyblock );*/
if( upd_trust )
- clear_trust_checked_flag( mainpk );
+ revalidation_mark ();
release_revocation_reason_info( reason );
return changed;
@@ -2202,20 +2204,17 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
static int
enable_disable_key( KBNODE keyblock, int disable )
{
- ulong lid = find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key->local_id;
+ PKT_public_key *pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )
+ ->pkt->pkt.public_key;
unsigned int trust, newtrust;
- /* Note: Because the keys have beed displayed, we have
- * ensured that local_id has been set */
- trust = newtrust = get_ownertrust( lid );
+ trust = newtrust = get_ownertrust (pk);
newtrust &= ~TRUST_FLAG_DISABLED;
if( disable )
newtrust |= TRUST_FLAG_DISABLED;
if( trust == newtrust )
return 0; /* already in that state */
- if( !update_ownertrust( lid, newtrust ) )
- return 1;
+ update_ownertrust(pk, newtrust );
return 0;
}
diff --git a/g10/keygen.c b/g10/keygen.c
index a6a2104f4..f30e49891 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -32,6 +32,7 @@
#include "ttyio.h"
#include "options.h"
#include "keydb.h"
+#include "trustdb.h"
#include "status.h"
#include "i18n.h"
@@ -1934,9 +1935,19 @@ do_generate_keypair( struct para_data_s *para,
get_parameter_algo(para, pKEYTYPE) == PUBKEY_ALGO_RSA
&& get_parameter_uint( para, pKEYUSAGE )
&& !(get_parameter_uint( para,pKEYUSAGE) & PUBKEY_USAGE_ENC);
+ PKT_public_key *pk = find_kbnode (pub_root,
+ PKT_PUBLIC_KEY)->pkt->pkt.public_key;
+
+ update_ownertrust (pk,
+ ((get_ownertrust (pk) & ~TRUST_MASK)
+ | TRUST_ULTIMATE ));
+
+ if (!opt.batch) {
+ tty_printf(_("public and secret key created and signed.\n") );
+ tty_printf(_("key marked as ultimately trusted.\n") );
+ }
+
- if( !opt.batch )
- tty_printf(_("public and secret key created and signed.\n") );
if( !opt.batch
&& ( get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
|| no_enc_rsa )
diff --git a/g10/keylist.c b/g10/keylist.c
index ff726e160..35ce75842 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -433,7 +433,7 @@ list_keyblock_colon( KBNODE keyblock, int secret )
else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
;
else {
- trustletter = query_trust_info( pk, NULL );
+ trustletter = get_validity_info ( pk, NULL );
if( trustletter == 'u' )
ulti_hack = 1;
putchar(trustletter);
@@ -449,7 +449,7 @@ list_keyblock_colon( KBNODE keyblock, int secret )
putchar(':');
if( pk->local_id && !opt.fast_list_mode
&& !opt.no_expensive_trust_checks )
- putchar( get_ownertrust_info( pk->local_id ) );
+ putchar( get_ownertrust_info(pk) );
putchar(':');
}
@@ -490,7 +490,7 @@ list_keyblock_colon( KBNODE keyblock, int secret )
rmd160_hash_buffer( namehash,
node->pkt->pkt.user_id->name,
node->pkt->pkt.user_id->len );
- trustletter = query_trust_info( pk, namehash );
+ trustletter = get_validity_info( pk, namehash );
}
else
trustletter = 'u';
diff --git a/g10/keyring.c b/g10/keyring.c
index fc4412d76..a55dcc621 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -678,7 +678,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
int save_mode;
off_t offset, main_offset;
size_t n;
- int need_uid, need_words, need_keyid, need_fpr;
+ int need_uid, need_words, need_keyid, need_fpr, any_skip;
int pk_no, uid_no;
int initial_skip;
PKT_user_id *uid = NULL;
@@ -686,7 +686,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
PKT_secret_key *sk = NULL;
/* figure out what information we need */
- need_uid = need_words = need_keyid = need_fpr = 0;
+ need_uid = need_words = need_keyid = need_fpr = any_skip = 0;
for (n=0; n < ndesc; n++) {
switch (desc[n].mode) {
case KEYDB_SEARCH_MODE_EXACT:
@@ -715,6 +715,10 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
break;
default: break;
}
+ if (desc[n].skipfnc) {
+ any_skip = 1;
+ need_keyid = 1;
+ }
}
rc = prepare_search (hd);
@@ -797,9 +801,6 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
case KEYDB_SEARCH_MODE_NONE:
BUG ();
break;
- case KEYDB_SEARCH_MODE_TDBIDX:
- BUG();
- break;
case KEYDB_SEARCH_MODE_EXACT:
case KEYDB_SEARCH_MODE_SUBSTR:
case KEYDB_SEARCH_MODE_MAIL:
@@ -831,6 +832,9 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
goto found;
break;
case KEYDB_SEARCH_MODE_FIRST:
+ if (pk||sk)
+ goto found;
+ break;
case KEYDB_SEARCH_MODE_NEXT:
if (pk||sk)
goto found;
@@ -840,10 +844,19 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
goto found;
}
}
-
+ free_packet (&pkt);
+ continue;
+ found:
+ for (n=any_skip?0:ndesc; n < ndesc; n++) {
+ if (desc[n].skipfnc
+ && desc[n].skipfnc (desc[n].skipfncvalue, aki))
+ break;
+ }
+ if (n == ndesc)
+ goto real_found;
free_packet (&pkt);
}
- found:
+ real_found:
if( !rc ) {
hd->found.offset = main_offset;
hd->found.kr = hd->current.kr;
diff --git a/g10/keyring.o b/g10/keyring.o
index 24f1f0460..a188ed024 100644
--- a/g10/keyring.o
+++ b/g10/keyring.o
Binary files differ
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 6e19825f1..f8db5fa0d 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -748,7 +748,7 @@ list_node( CTX c, KBNODE node )
if( mainkey ) {
c->local_id = pk->local_id;
c->trustletter = opt.fast_list_mode?
- 0 : query_trust_info( pk, NULL );
+ 0 : get_validity_info( pk, NULL );
}
printf("%s:", mainkey? "pub":"sub" );
if( c->trustletter )
@@ -762,8 +762,8 @@ list_node( CTX c, KBNODE node )
if( c->local_id )
printf("%lu", c->local_id );
putchar(':');
- if( c->local_id && !opt.fast_list_mode )
- putchar( get_ownertrust_info( c->local_id ) );
+ if( mainkey && !opt.fast_list_mode )
+ putchar( get_ownertrust_info (pk) );
putchar(':');
if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) {
putchar('\n'); any=1;
diff --git a/g10/options.h b/g10/options.h
index dc691693f..b6cf4a668 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -114,6 +114,7 @@ struct {
int no_expensive_trust_checks;
int no_sig_cache;
int no_sig_create_check;
+ int no_auto_check_trustdb;
int preserve_permissions;
int no_homedir_creation;
} opt;
diff --git a/g10/pkclist.c b/g10/pkclist.c
index d596d166b..af5813231 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -149,8 +149,10 @@ show_revocation_reason( PKT_public_key *pk )
static void
-show_paths( ulong lid, int only_first )
+show_paths (const PKT_public_key *pk, int only_first )
{
+#warning must change enum_cert_paths to use pk
+#if 0
void *context = NULL;
unsigned otrust, validity;
int last_level, level;
@@ -168,6 +170,7 @@ show_paths( ulong lid, int only_first )
last_level = level;
rc = keyid_from_lid( lid, keyid );
+
if( rc ) {
log_error("ooops: can't get keyid for lid %lu\n", lid);
return;
@@ -206,6 +209,7 @@ show_paths( ulong lid, int only_first )
free_public_key( pk );
}
enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */
+#endif
tty_printf("\n");
}
@@ -213,143 +217,144 @@ show_paths( ulong lid, int only_first )
/****************
- * Returns true if an ownertrust has changed.
+ * mode: 0 = standard
+ * 1 = Without key info and additional menu option 'm'
+ * Returns:
+ * -2 = nothing changed - caller should show some additional info
+ * -1 = quit operation
+ * 0 = nothing changed
+ * 1 = new ownertrust now ion new_trust
*/
static int
-do_edit_ownertrust( ulong lid, int mode, unsigned *new_trust, int defer_help )
+do_edit_ownertrust (PKT_public_key *pk, int mode,
+ unsigned *new_trust, int defer_help )
{
- char *p;
- int rc;
- size_t n;
- u32 keyid[2];
- PKT_public_key *pk ;
- int changed=0;
- int quit=0;
- int show=0;
- int did_help=defer_help;
-
- rc = keyid_from_lid( lid, keyid );
- if( rc ) {
- log_error("ooops: can't get keyid for lid %lu\n", lid);
- return 0;
- }
-
- pk = m_alloc_clear( sizeof *pk );
- rc = get_pubkey( pk, keyid );
- if( rc ) {
- log_error("key %08lX: public key not found: %s\n",
- (ulong)keyid[1], g10_errstr(rc) );
- return 0;
- }
-
-
- for(;;) {
- /* a string with valid answers */
- const char *ans = _("sSmMqQ");
-
- if( !did_help ) {
- if( !mode ) {
- tty_printf(_("No trust value assigned to %lu:\n"
- "%4u%c/%08lX %s \""), lid,
- nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1], datestr_from_pk( pk ) );
- p = get_user_id( keyid, &n );
- tty_print_utf8_string( p, n ),
- m_free(p);
- tty_printf("\"\n");
- print_fingerprint (pk, NULL, 2);
- tty_printf("\n");
- }
- tty_printf(_(
-"Please decide how far you trust this user to correctly\n"
-"verify other users' keys (by looking at passports,\n"
-"checking fingerprints from different sources...)?\n\n"
-" 1 = Don't know\n"
-" 2 = I do NOT trust\n"
-" 3 = I trust marginally\n"
-" 4 = I trust fully\n"
-" s = please show me more information\n") );
- if( mode )
- tty_printf(_(" m = back to the main menu\n"));
- else
- tty_printf(_(" q = quit\n"));
- tty_printf("\n");
- did_help = 1;
- }
- if( strlen(ans) != 6 )
- BUG();
- p = cpr_get("edit_ownertrust.value",_("Your decision? "));
- trim_spaces(p);
- cpr_kill_prompt();
- if( !*p )
- did_help = 0;
- else if( *p && p[1] )
- ;
- else if( !p[1] && (*p >= '1' && *p <= '4') ) {
- unsigned trust;
- switch( *p ) {
- case '1': trust = TRUST_UNDEFINED; break;
- case '2': trust = TRUST_NEVER ; break;
- case '3': trust = TRUST_MARGINAL ; break;
- case '4': trust = TRUST_FULLY ; break;
- default: BUG();
- }
- *new_trust = trust;
- changed = 1;
- break;
- }
- else if( *p == ans[0] || *p == ans[1] ) {
- tty_printf(_(
- "Certificates leading to an ultimately trusted key:\n"));
- show = 1;
- break;
- }
- else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) {
- break ; /* back to the menu */
- }
- else if( !mode && (*p == ans[4] || *p == ans[5] ) ) {
- quit = 1;
- break ; /* back to the menu */
- }
- m_free(p); p = NULL;
- }
- m_free(p);
- m_free(pk);
- return show? -2: quit? -1 : changed;
+ char *p;
+ size_t n;
+ u32 keyid[2];
+ int changed=0;
+ int quit=0;
+ int show=0;
+ int did_help=defer_help;
+
+ keyid_from_pk (pk, keyid);
+ for(;;) {
+ /* a string with valid answers */
+ const char *ans = _("sSmMqQ");
+
+ if( !did_help )
+ {
+ if( !mode )
+ {
+ tty_printf(_("No trust value assigned to:\n"
+ "%4u%c/%08lX %s \""),
+ nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid[1], datestr_from_pk( pk ) );
+ p = get_user_id( keyid, &n );
+ tty_print_utf8_string( p, n ),
+ m_free(p);
+ tty_printf("\"\n");
+ print_fingerprint (pk, NULL, 2);
+ tty_printf("\n");
+ }
+ tty_printf(_(
+ "Please decide how far you trust this user to correctly\n"
+ "verify other users' keys (by looking at passports,\n"
+ "checking fingerprints from different sources...)?\n\n"
+ " 1 = Don't know\n"
+ " 2 = I do NOT trust\n"
+ " 3 = I trust marginally\n"
+ " 4 = I trust fully\n"
+ " s = please show me more information\n") );
+ if( mode )
+ tty_printf(_(" m = back to the main menu\n"));
+ else
+ tty_printf(_(" q = quit\n"));
+ tty_printf("\n");
+ did_help = 1;
+ }
+ if( strlen(ans) != 6 )
+ BUG();
+ p = cpr_get("edit_ownertrust.value",_("Your decision? "));
+ trim_spaces(p);
+ cpr_kill_prompt();
+ if( !*p )
+ did_help = 0;
+ else if( *p && p[1] )
+ ;
+ else if( !p[1] && (*p >= '1' && *p <= '4') )
+ {
+ unsigned trust;
+ switch( *p )
+ {
+ case '1': trust = TRUST_UNDEFINED; break;
+ case '2': trust = TRUST_NEVER ; break;
+ case '3': trust = TRUST_MARGINAL ; break;
+ case '4': trust = TRUST_FULLY ; break;
+ default: BUG();
+ }
+ *new_trust = trust;
+ changed = 1;
+ break;
+ }
+ else if( *p == ans[0] || *p == ans[1] )
+ {
+ tty_printf(_("Certificates leading to an ultimately trusted key:\n"));
+ show = 1;
+ break;
+ }
+ else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) )
+ {
+ break ; /* back to the menu */
+ }
+ else if( !mode && (*p == ans[4] || *p == ans[5] ) )
+ {
+ quit = 1;
+ break ; /* back to the menu */
+ }
+ m_free(p); p = NULL;
+ }
+ m_free(p);
+ return show? -2: quit? -1 : changed;
}
-
+/*
+ * Display a menu to change the ownertrust of the key PK (which should
+ * be a primary key).
+ * For mode values see do_edit_ownertrust ()
+ */
int
-edit_ownertrust( ulong lid, int mode )
+edit_ownertrust (PKT_public_key *pk, int mode )
{
- unsigned int trust;
- int no_help = 0;
-
- for(;;) {
- switch( do_edit_ownertrust( lid, mode, &trust, no_help ) ) {
- case -1:
- return 0;
- case -2:
- show_paths( lid, 1 );
- no_help = 1;
- break;
- case 1:
- trust &= ~TRUST_FLAG_DISABLED;
- trust |= get_ownertrust( lid ) & TRUST_FLAG_DISABLED;
- if( !update_ownertrust( lid, trust ) )
- return 1;
- return 0;
- default:
- return 0;
- }
+ unsigned int trust;
+ int no_help = 0;
+
+ for(;;)
+ {
+ switch ( do_edit_ownertrust (pk, mode, &trust, no_help ) )
+ {
+ case -1: /* quit */
+ return 0;
+ case -2: /* show info */
+ show_paths(pk, 1);
+ no_help = 1;
+ break;
+ case 1: /* trust value set */
+ trust &= ~TRUST_FLAG_DISABLED;
+ trust |= get_ownertrust (pk) & TRUST_FLAG_DISABLED;
+ update_ownertrust (pk, trust );
+ return 0;
+ default:
+ return 0;
+ }
}
}
static int
-add_ownertrust_cb( ulong lid )
+add_ownertrust_cb (PKT_public_key *pk )
{
- unsigned trust;
- int rc = do_edit_ownertrust( lid, 0, &trust, 0 );
+ unsigned int trust;
+ int rc = do_edit_ownertrust (pk, 0, &trust, 0 );
if( rc == 1 )
return trust & TRUST_MASK;
@@ -368,13 +373,14 @@ add_ownertrust( PKT_public_key *pk, int *quit, int *trustlevel )
int rc;
unsigned flags = 0;
+#warning This function does not make sense anymore
*quit = 0;
*trustlevel = 0;
tty_printf(
_("Could not find a valid trust path to the key. Let's see whether we\n"
"can assign some missing owner trust values.\n\n"));
- rc = check_trust( pk, trustlevel, NULL, add_ownertrust_cb, &flags );
+ *trustlevel = get_validity ( pk, NULL);
if( !(flags & 1) )
tty_printf(_("No path leading to one of our keys found.\n\n") );
@@ -436,17 +442,8 @@ do_we_trust( PKT_public_key *pk, int *trustlevel )
switch( (*trustlevel & TRUST_MASK) ) {
case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error("failed to insert it into the trustdb: %s\n",
- g10_errstr(rc) );
- return 0; /* no */
- }
- rc = check_trust( pk, trustlevel, NULL, NULL, NULL );
+ *trustlevel = get_validity (pk, NULL);
*trustlevel &= ~trustmask;
- if( rc )
- log_fatal("trust check after insert failed: %s\n",
- g10_errstr(rc) );
if( *trustlevel == TRUST_UNKNOWN || *trustlevel == TRUST_EXPIRED ) {
log_debug("do_we_trust: oops at %d\n", __LINE__ );
return 0;
@@ -587,11 +584,7 @@ check_signatures_trust( PKT_signature *sig )
goto leave;
}
- rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
- if( rc ) {
- log_error("check trust failed: %s\n", g10_errstr(rc));
- goto leave;
- }
+ trustlevel = get_validity (pk, NULL);
retry:
if( (trustlevel & TRUST_FLAG_REVOKED) ) {
@@ -609,16 +602,7 @@ check_signatures_trust( PKT_signature *sig )
switch( (trustlevel & TRUST_MASK) ) {
case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error("failed to insert it into the trustdb: %s\n",
- g10_errstr(rc) );
- goto leave;
- }
- rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
- if( rc )
- log_fatal("trust check after insert failed: %s\n",
- g10_errstr(rc) );
+ trustlevel = get_validity (pk, NULL);
if( trustlevel == TRUST_UNKNOWN || trustlevel == TRUST_EXPIRED )
BUG();
goto retry;
@@ -851,13 +835,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
else {
int trustlevel;
- rc = check_trust( pk, &trustlevel, pk->namehash,
- NULL, NULL );
- if( rc ) {
- log_error("error checking pk of `%s': %s\n",
- answer, g10_errstr(rc) );
- }
- else if( (trustlevel & TRUST_FLAG_DISABLED) ) {
+ trustlevel = get_validity (pk, NULL);
+ if( (trustlevel & TRUST_FLAG_DISABLED) ) {
tty_printf(_("Public key is disabled.\n") );
}
else if( do_we_trust_pre( pk, trustlevel ) ) {
@@ -929,17 +908,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
int trustlevel;
- rc = check_trust( pk, &trustlevel, pk->namehash, NULL, NULL );
- if( rc ) {
- free_public_key( pk ); pk = NULL;
- log_error(_("%s: error checking key: %s\n"),
- remusr->d, g10_errstr(rc) );
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- remusr->d,
- strlen (remusr->d),
- -1);
- }
- else if( (trustlevel & TRUST_FLAG_DISABLED) ) {
+ trustlevel = get_validity (pk, pk->namehash);
+ if( (trustlevel & TRUST_FLAG_DISABLED) ) {
free_public_key(pk); pk = NULL;
log_info(_("%s: skipped: public key is disabled\n"),
remusr->d);
diff --git a/g10/tdbdump.c b/g10/tdbdump.c
index b44cdbd95..092d18257 100644
--- a/g10/tdbdump.c
+++ b/g10/tdbdump.c
@@ -46,22 +46,7 @@
#define HEXTOBIN(x) ( (x) >= '0' && (x) <= '9' ? ((x)-'0') : \
(x) >= 'A' && (x) <= 'F' ? ((x)-'A'+10) : ((x)-'a'+10))
-/****************
- * Read a record but die if it does not exist
- * fixme: duplicate: remove it
- */
-#if 0
-static void
-read_record( ulong recno, TRUSTREC *rec, int rectype )
-{
- int rc = tdbio_read_record( recno, rec, rectype );
- if( !rc )
- return;
- log_error(_("trust record %lu, req type %d: read failed: %s\n"),
- recno, rectype, g10_errstr(rc) );
- tdbio_invalid();
-}
-#endif
+
/****************
* Wirte a record but die on error
*/
@@ -78,256 +63,6 @@ write_record( TRUSTREC *rec )
/****************
- * sync the db
- */
-static void
-do_sync(void)
-{
- int rc = tdbio_sync();
- if( !rc )
- return;
- log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
- g10_exit(2);
-}
-
-#if 0
-static int
-print_sigflags( FILE *fp, unsigned flags )
-{
- if( flags & SIGF_CHECKED ) {
- fprintf(fp,"%c%c%c",
- (flags & SIGF_VALID) ? 'V':'-',
- (flags & SIGF_EXPIRED) ? 'E':'-',
- (flags & SIGF_REVOKED) ? 'R':'-');
- }
- else if( flags & SIGF_NOPUBKEY)
- fputs("?--", fp);
- else
- fputs("---", fp);
- return 3;
-}
-#endif
-
-
-/****************
- * Walk through the signatures of a public key.
- * The caller must provide a context structure, with all fields set
- * to zero, but the local_id field set to the requested key;
- * This function does not change this field. On return the context
- * is filled with the local-id of the signature and the signature flag.
- * No fields should be changed (clearing all fields and setting
- * pubkeyid is okay to continue with an other pubkey)
- * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
- * FIXME: Do we really need this large and complicated function?
- */
-#if 0
-static int
-walk_sigrecs( SIGREC_CONTEXT *c )
-{
- TRUSTREC *r;
- ulong rnum;
-
- if( c->ctl.eof )
- return -1;
- r = &c->ctl.rec;
- if( !c->ctl.init_done ) {
- c->ctl.init_done = 1;
- read_record( c->lid, r, 0 );
- if( r->rectype != RECTYPE_DIR ) {
- c->ctl.eof = 1;
- return -1; /* return eof */
- }
- c->ctl.nextuid = r->r.dir.uidlist;
- /* force a read */
- c->ctl.index = SIGS_PER_RECORD;
- r->r.sig.next = 0;
- }
-
- /* need a loop to skip over deleted sigs */
- do {
- if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
- rnum = r->r.sig.next;
- if( !rnum && c->ctl.nextuid ) { /* read next uid record */
- read_record( c->ctl.nextuid, r, RECTYPE_UID );
- c->ctl.nextuid = r->r.uid.next;
- rnum = r->r.uid.siglist;
- }
- if( !rnum ) {
- c->ctl.eof = 1;
- return -1; /* return eof */
- }
- read_record( rnum, r, RECTYPE_SIG );
- if( r->r.sig.lid != c->lid ) {
- log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
- c->ctl.eof = 1;
- tdbio_invalid();
- }
- c->ctl.index = 0;
- }
- } while( !r->r.sig.sig[c->ctl.index++].lid );
-
- c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
- c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
- return 0;
-}
-#endif
-
-#if 0
-static int
-do_list_sigs( ulong root, ulong pk_lid, int depth,
- LOCAL_ID_TABLE lids, unsigned *lineno )
-{
- SIGREC_CONTEXT sx;
- int rc;
- u32 keyid[2];
-
- memset( &sx, 0, sizeof sx );
- sx.lid = pk_lid;
- for(;;) {
- rc = walk_sigrecs( &sx ); /* should we replace it and use */
- if( rc )
- break;
- rc = keyid_from_lid( sx.sig_lid, keyid );
- if( rc ) {
- printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
- print_sigflags( stdout, sx.sig_flag );
- putchar('\n');
- ++*lineno;
- }
- else {
- printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
- (ulong)keyid[1], sx.sig_lid );
- print_sigflags( stdout, sx.sig_flag );
- putchar(' ');
- /* check whether we already checked this pk_lid */
- if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
- print_user_id("[ultimately trusted]", keyid);
- ++*lineno;
- }
- else if( sx.sig_lid == pk_lid ) {
- printf("[self-signature]\n");
- ++*lineno;
- }
- else if( sx.sig_lid == root ) {
- printf("[closed]\n");
- ++*lineno;
- }
- else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
- unsigned refline;
- qry_lid_table_flag( lids, sx.sig_lid, &refline );
- printf("[see line %u]\n", refline);
- ++*lineno;
- }
- else if( depth+1 >= MAX_LIST_SIGS_DEPTH ) {
- print_user_id( "[too deeply nested]", keyid );
- ++*lineno;
- }
- else {
- print_user_id( "", keyid );
- ++*lineno;
- rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
- if( rc )
- break;
- }
- }
- }
- return rc==-1? 0 : rc;
-}
-#endif
-/****************
- * List all signatures of a public key
- */
-static int
-list_sigs( ulong pubkey_id )
-{
- int rc=0;
- #if 0
- u32 keyid[2];
- LOCAL_ID_TABLE lids;
- unsigned lineno = 1;
-
- rc = keyid_from_lid( pubkey_id, keyid );
- if( rc )
- return rc;
- printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
- print_user_id("", keyid);
- printf("----------------------\n");
-
- lids = new_lid_table();
- rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
- putchar('\n');
- release_lid_table(lids);
- #endif
- return rc;
-}
-
-/****************
- * List all records of a public key
- */
-static int
-list_records( ulong lid )
-{
- int rc;
- TRUSTREC dr, ur, rec;
- ulong recno;
-
- rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
- if( rc ) {
- log_error(_("lid %lu: read dir record failed: %s\n"),
- lid, g10_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &dr, stdout );
-
- for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
- rc = tdbio_read_record( recno, &rec, 0 );
- if( rc ) {
- log_error(_("lid %lu: read key record failed: %s\n"),
- lid, g10_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &rec, stdout );
- }
-
- for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
- rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
- if( rc ) {
- log_error(_("lid %lu: read uid record failed: %s\n"),
- lid, g10_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &ur, stdout );
- /* preference records */
- for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
- rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
- if( rc ) {
- log_error(_("lid %lu: read pref record failed: %s\n"),
- lid, g10_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &rec, stdout );
- }
- /* sig records */
- for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
- rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
- if( rc ) {
- log_error(_("lid %lu: read sig record failed: %s\n"),
- lid, g10_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &rec, stdout );
- }
- }
-
- /* add cache record dump here */
-
-
-
- return rc;
-}
-
-
-/****************
* Dump the entire trustdb or only the entries of one key.
*/
void
@@ -336,38 +71,8 @@ list_trustdb( const char *username )
TRUSTREC rec;
init_trustdb();
-
- if( username && *username == '#' ) {
- int rc;
- ulong lid = atoi(username+1);
-
- if( (rc = list_records( lid)) )
- log_error(_("user '%s' read problem: %s\n"),
- username, g10_errstr(rc));
- else if( (rc = list_sigs( lid )) )
- log_error(_("user '%s' list problem: %s\n"),
- username, g10_errstr(rc));
- }
- else if( username ) {
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
- int rc;
-
- if( (rc = get_pubkey_byname( pk, username, NULL, NULL )) )
- log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
- else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
- log_error(_("problem finding '%s' in trustdb: %s\n"),
- username, g10_errstr(rc));
- else if( rc == -1 )
- log_error(_("user '%s' not in trustdb\n"), username);
- else if( (rc = list_records( pk->local_id)) )
- log_error(_("user '%s' read problem: %s\n"),
- username, g10_errstr(rc));
- else if( (rc = list_sigs( pk->local_id )) )
- log_error(_("user '%s' list problem: %s\n"),
- username, g10_errstr(rc));
- free_public_key( pk );
- }
- else {
+ /* for now we ignore the user ID */
+ if (1) {
ulong recnum;
int i;
@@ -391,33 +96,22 @@ void
export_ownertrust()
{
TRUSTREC rec;
- TRUSTREC rec2;
ulong recnum;
int i;
byte *p;
- int rc;
init_trustdb();
printf(_("# List of assigned trustvalues, created %s\n"
"# (Use \"gpg --import-ownertrust\" to restore them)\n"),
asctimestamp( make_timestamp() ) );
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- if( rec.rectype == RECTYPE_DIR ) {
- if( !rec.r.dir.keylist ) {
- log_error(_("directory record w/o primary key\n"));
+ if( rec.rectype == RECTYPE_TRUST ) {
+ if( !rec.r.trust.ownertrust )
continue;
- }
- if( !rec.r.dir.ownertrust )
- continue;
- rc = tdbio_read_record( rec.r.dir.keylist, &rec2, RECTYPE_KEY);
- if( rc ) {
- log_error(_("error reading key record: %s\n"), g10_errstr(rc));
- continue;
- }
- p = rec2.r.key.fingerprint;
- for(i=0; i < rec2.r.key.fingerprint_len; i++, p++ )
+ p = rec.r.trust.fingerprint;
+ for(i=0; i < 20; i++, p++ )
printf("%02X", *p );
- printf(":%u:\n", (unsigned)rec.r.dir.ownertrust );
+ printf(":%u:\n", (unsigned int)rec.r.trust.ownertrust );
}
}
}
@@ -431,7 +125,9 @@ import_ownertrust( const char *fname )
char line[256];
char *p;
size_t n, fprlen;
- unsigned otrust;
+ unsigned int otrust;
+ byte fpr[20];
+ int any = 0;
init_trustdb();
if( !fname || (*fname == '-' && !fname[1]) ) {
@@ -475,51 +171,45 @@ import_ownertrust( const char *fname )
if( !otrust )
continue; /* no otrust defined - no need to update or insert */
/* convert the ascii fingerprint to binary */
- for(p=line, fprlen=0; *p != ':'; p += 2 )
- line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
- line[fprlen] = 0;
-
- repeat:
- rc = tdbio_search_dir_byfpr( line, fprlen, 0, &rec );
+ for(p=line, fprlen=0; fprlen < 20 && *p != ':'; p += 2 )
+ fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
+ while (fprlen < 20)
+ fpr[fprlen++] = 0;
+
+ rc = tdbio_search_trust_byfpr (fpr, &rec);
if( !rc ) { /* found: update */
- if( rec.r.dir.ownertrust )
- log_info("LID %lu: changing trust from %u to %u\n",
- rec.r.dir.lid, rec.r.dir.ownertrust, otrust );
- else
- log_info("LID %lu: setting trust to %u\n",
- rec.r.dir.lid, otrust );
- rec.r.dir.ownertrust = otrust;
- write_record( &rec );
+ if (rec.r.trust.ownertrust != otrust)
+ {
+ if( rec.r.trust.ownertrust )
+ log_info("changing ownertrust from %u to %u\n",
+ rec.r.trust.ownertrust, otrust );
+ else
+ log_info("setting ownertrust to %u\n", otrust );
+ rec.r.trust.ownertrust = otrust;
+ write_record (&rec );
+ any = 1;
+ }
}
- else if( rc == -1 ) { /* not found; get the key from the ring */
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-
- log_info_f(fname, _("key not in trustdb, searching ring.\n"));
- rc = get_pubkey_byfprint( pk, line, fprlen );
- if( rc )
- log_info_f(fname, _("key not in ring: %s\n"), g10_errstr(rc));
- else {
- rc = query_trust_record( pk ); /* only as assertion */
- if( rc != -1 )
- log_error_f(fname, _("Oops: key is now in trustdb???\n"));
- else {
- rc = insert_trust_record_by_pk( pk );
- if( !rc )
- goto repeat; /* update the ownertrust */
- log_error_f(fname, _("insert trust record failed: %s\n"),
- g10_errstr(rc) );
- }
- }
+ else if( rc == -1 ) { /* not found: insert */
+ log_info("inserting ownertrust of %u\n", otrust );
+ memset (&rec, 0, sizeof rec);
+ rec.recnum = tdbio_new_recnum ();
+ rec.rectype = RECTYPE_TRUST;
+ memcpy (rec.r.trust.fingerprint, fpr, 20);
+ rec.r.trust.ownertrust = otrust;
+ write_record (&rec );
+ any = 1;
}
else /* error */
- log_error_f(fname, _("error finding dir record: %s\n"),
+ log_error_f(fname, _("error finding trust record: %s\n"),
g10_errstr(rc));
}
if( ferror(fp) )
log_error_f(fname, _("read error: %s\n"), strerror(errno) );
if( !is_stdin )
fclose(fp);
- do_sync();
- sync_trustdb();
+
+ if (any)
+ revalidation_mark ();
}
diff --git a/g10/tdbio.c b/g10/tdbio.c
index de900e7ee..0ef1ec086 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -83,6 +83,8 @@ static int db_fd = -1;
static int in_transaction;
static void open_db(void);
+static void migrate_from_v2 (void);
+
/*************************************
@@ -406,6 +408,28 @@ cleanup(void)
}
}
+static int
+create_version_record (void)
+{
+ TRUSTREC rec;
+ int rc;
+
+ memset( &rec, 0, sizeof rec );
+ rec.r.ver.version = 3;
+ rec.r.ver.created = make_timestamp();
+ rec.r.ver.marginals = opt.marginals_needed;
+ rec.r.ver.completes = opt.completes_needed;
+ rec.r.ver.cert_depth = opt.max_cert_depth;
+ rec.rectype = RECTYPE_VER;
+ rec.recnum = 0;
+ rc = tdbio_write_record( &rec );
+ if( !rc )
+ tdbio_sync();
+ return rc;
+}
+
+
+
int
tdbio_set_dbname( const char *new_dbname, int create )
{
@@ -469,17 +493,7 @@ tdbio_set_dbname( const char *new_dbname, int create )
log_fatal( _("%s: can't create lock\n"), db_name );
#endif /* !__riscos__ */
- memset( &rec, 0, sizeof rec );
- rec.r.ver.version = 2;
- rec.r.ver.created = make_timestamp();
- rec.r.ver.marginals = opt.marginals_needed;
- rec.r.ver.completes = opt.completes_needed;
- rec.r.ver.cert_depth = opt.max_cert_depth;
- rec.rectype = RECTYPE_VER;
- rec.recnum = 0;
- rc = tdbio_write_record( &rec );
- if( !rc )
- tdbio_sync();
+ rc = create_version_record ();
if( rc )
log_fatal( _("%s: failed to create version record: %s"),
fname, g10_errstr(rc));
@@ -510,31 +524,45 @@ tdbio_get_dbname()
static void
open_db()
{
- TRUSTREC rec;
- assert( db_fd == -1 );
+ byte buf[10];
+ int n;
+ TRUSTREC rec;
- if( !lockhandle )
- lockhandle = create_dotlock( db_name );
- if( !lockhandle )
- log_fatal( _("%s: can't create lock\n"), db_name );
+ assert( db_fd == -1 );
+
+ if (!lockhandle )
+ lockhandle = create_dotlock( db_name );
+ if (!lockhandle )
+ log_fatal( _("%s: can't create lock\n"), db_name );
#ifdef __riscos__
- if( make_dotlock( lockhandle, -1 ) )
- log_fatal( _("%s: can't make lock\n"), db_name );
+ if (make_dotlock( lockhandle, -1 ) )
+ log_fatal( _("%s: can't make lock\n"), db_name );
#endif /* __riscos__ */
- #ifdef HAVE_DOSISH_SYSTEM
- db_fd = open( db_name, O_RDWR | O_BINARY );
- #else
- db_fd = open( db_name, O_RDWR );
- #endif
- if( db_fd == -1 )
- log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
- if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
- log_fatal( _("%s: invalid trustdb\n"), db_name );
+#ifdef HAVE_DOSISH_SYSTEM
+ db_fd = open (db_name, O_RDWR | O_BINARY );
+#else
+ db_fd = open (db_name, O_RDWR );
+#endif
+ if ( db_fd == -1 )
+ log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
+
+ /* check whether we need to do a version migration */
+ do
+ n = read (db_fd, buf, 5);
+ while (n==-1 && errno == EINTR);
+ if (n == 5 && !memcmp (buf, "\x01gpg\x02", 5))
+ {
+ migrate_from_v2 ();
+ }
+
+ /* read the version record */
+ if (tdbio_read_record (0, &rec, RECTYPE_VER ) )
+ log_fatal( _("%s: invalid trustdb\n"), db_name );
}
/****************
- * Make a hashtable: type 0 = key hash, 1 = sdir hash
+ * Make a hashtable: type 0 = trust hash
*/
static void
create_hashtable( TRUSTREC *vr, int type )
@@ -551,9 +579,8 @@ create_hashtable( TRUSTREC *vr, int type )
assert(recnum); /* this is will never be the first record */
if( !type )
- vr->r.ver.keyhashtbl = recnum;
- else
- vr->r.ver.sdirhashtbl = recnum;
+ vr->r.ver.trusthashtbl = recnum;
+
/* Now write the records */
n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
for(i=0; i < n; i++, recnum++ ) {
@@ -612,50 +639,36 @@ tdbio_db_matches_options()
/****************
- * Return the modifiy stamp.
- * if modify_down is true, the modify_down stamp will be
- * returned, otherwise the modify_up stamp.
+ * Return the nextstamp value.
*/
ulong
-tdbio_read_modify_stamp( int modify_down )
+tdbio_read_nextcheck ()
{
TRUSTREC vr;
int rc;
- ulong mod;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
db_name, g10_errstr(rc) );
-
- mod = modify_down? vr.r.ver.mod_down : vr.r.ver.mod_up;
-
- /* Always return at least 1 to make comparison easier;
- * this is still far back in history (before Led Zeppelin III :-) */
- return mod ? mod : 1;
+ return vr.r.ver.nextcheck;
}
void
-tdbio_write_modify_stamp( int up, int down )
+tdbio_write_nextcheck (ulong stamp)
{
TRUSTREC vr;
int rc;
- ulong stamp;
-
- if( !(up || down) )
- return;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
db_name, g10_errstr(rc) );
- stamp = make_timestamp();
- if( down )
- vr.r.ver.mod_down = stamp;
- if( up )
- vr.r.ver.mod_up = stamp;
+ if (vr.r.ver.nextcheck == stamp)
+ return;
+ vr.r.ver.nextcheck = stamp;
rc = tdbio_write_record( &vr );
if( rc )
log_fatal( _("%s: error writing version record: %s\n"),
@@ -663,15 +676,16 @@ tdbio_write_modify_stamp( int up, int down )
}
+
/****************
- * Return the record number of the keyhash tbl or create a new one.
+ * Return the record number of the trusthash tbl or create a new one.
*/
static ulong
-get_keyhashrec(void)
+get_trusthashrec(void)
{
- static ulong keyhashtbl; /* record number of the key hashtable */
+ static ulong trusthashtbl; /* record number of the trust hashtable */
- if( !keyhashtbl ) {
+ if( !trusthashtbl ) {
TRUSTREC vr;
int rc;
@@ -679,38 +693,14 @@ get_keyhashrec(void)
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
db_name, g10_errstr(rc) );
- if( !vr.r.ver.keyhashtbl )
+ if( !vr.r.ver.trusthashtbl )
create_hashtable( &vr, 0 );
- keyhashtbl = vr.r.ver.keyhashtbl;
+ trusthashtbl = vr.r.ver.trusthashtbl;
}
- return keyhashtbl;
+ return trusthashtbl;
}
-/****************
- * Return the record number of the shadow direcory hash table
- * or create a new one.
- */
-static ulong
-get_sdirhashrec(void)
-{
- static ulong sdirhashtbl; /* record number of the hashtable */
-
- if( !sdirhashtbl ) {
- TRUSTREC vr;
- int rc;
-
- rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
- if( rc )
- log_fatal( _("%s: error reading version record: %s\n"),
- db_name, g10_errstr(rc) );
- if( !vr.r.ver.sdirhashtbl )
- create_hashtable( &vr, 1 );
-
- sdirhashtbl = vr.r.ver.sdirhashtbl;
- }
- return sdirhashtbl;
-}
/****************
@@ -827,9 +817,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
}
} /* end loop over hlst slots */
}
- else if( rec.rectype == RECTYPE_KEY
- || rec.rectype == RECTYPE_DIR
- || rec.rectype == RECTYPE_SDIR ) { /* insert a list record */
+ else if( rec.rectype == RECTYPE_TRUST ) { /* insert a list record */
if( rec.recnum == newrecnum ) {
return 0;
}
@@ -1036,57 +1024,16 @@ lookup_hashtable( ulong table, const byte *key, size_t keylen,
}
-
-
/****************
- * Update the key hashtbl or create the table if it does not exist
+ * Update the trust hashtbl or create the table if it does not exist
*/
static int
-update_keyhashtbl( TRUSTREC *kr )
+update_trusthashtbl( TRUSTREC *tr )
{
- return upd_hashtable( get_keyhashrec(),
- kr->r.key.fingerprint,
- kr->r.key.fingerprint_len, kr->recnum );
+ return upd_hashtable( get_trusthashrec(),
+ tr->r.trust.fingerprint, 20, tr->recnum );
}
-/****************
- * Update the shadow dir hashtbl or create the table if it does not exist
- */
-static int
-update_sdirhashtbl( TRUSTREC *sr )
-{
- byte key[8];
-
- u32tobuf( key , sr->r.sdir.keyid[0] );
- u32tobuf( key+4 , sr->r.sdir.keyid[1] );
- return upd_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
-}
-
-/****************
- * Drop the records from the key-hashtbl
- */
-static int
-drop_from_keyhashtbl( TRUSTREC *kr )
-{
- return drop_from_hashtable( get_keyhashrec(),
- kr->r.key.fingerprint,
- kr->r.key.fingerprint_len, kr->recnum );
-}
-
-/****************
- * Drop record drom the shadow dir hashtbl
- */
-static int
-drop_from_sdirhashtbl( TRUSTREC *sr )
-{
- byte key[8];
-
- u32tobuf( key , sr->r.sdir.keyid[0] );
- u32tobuf( key+4 , sr->r.sdir.keyid[1] );
- return drop_from_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
-}
-
-
void
@@ -1094,7 +1041,6 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
{
int i;
ulong rnum = rec->recnum;
- byte *p;
fprintf(fp, "rec %5lu, ", rnum );
@@ -1102,116 +1048,18 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
case 0: fprintf(fp, "blank\n");
break;
case RECTYPE_VER: fprintf(fp,
- "version, kd=%lu, sd=%lu, free=%lu, m/c/d=%d/%d/%d down=%s",
- rec->r.ver.keyhashtbl, rec->r.ver.sdirhashtbl,
+ "version, td=%lu, f=%lu, m/c/d=%d/%d/%d nc=%lu (%s)\n",
+ rec->r.ver.trusthashtbl,
rec->r.ver.firstfree,
rec->r.ver.marginals,
rec->r.ver.completes,
rec->r.ver.cert_depth,
- strtimestamp(rec->r.ver.mod_down) );
- fprintf(fp, ", up=%s\n", strtimestamp(rec->r.ver.mod_up) );
+ rec->r.ver.nextcheck,
+ strtimestamp(rec->r.ver.nextcheck)
+ );
break;
case RECTYPE_FREE: fprintf(fp, "free, next=%lu\n", rec->r.free.next );
break;
- case RECTYPE_DIR:
- fprintf(fp, "dir %lu, keys=%lu, uids=%lu, t=%02x",
- rec->r.dir.lid,
- rec->r.dir.keylist,
- rec->r.dir.uidlist,
- rec->r.dir.ownertrust );
- if( rec->r.dir.valcheck )
- fprintf( fp, ", v=%02x/%s", rec->r.dir.validity,
- strtimestamp(rec->r.dir.valcheck) );
- if( rec->r.dir.checkat )
- fprintf( fp, ", a=%s", strtimestamp(rec->r.dir.checkat) );
- if( rec->r.dir.dirflags & DIRF_CHECKED ) {
- if( rec->r.dir.dirflags & DIRF_VALID )
- fputs(", valid", fp );
- if( rec->r.dir.dirflags & DIRF_EXPIRED )
- fputs(", expired", fp );
- if( rec->r.dir.dirflags & DIRF_REVOKED )
- fputs(", revoked", fp );
- if( rec->r.dir.dirflags & DIRF_NEWKEYS )
- fputs(", newkeys", fp );
- }
- putc('\n', fp);
- break;
- case RECTYPE_KEY:
- fprintf(fp, "key %lu, n=%lu a=%d ",
- rec->r.key.lid,
- rec->r.key.next,
- rec->r.key.pubkey_algo );
- for(i=0; i < rec->r.key.fingerprint_len; i++ )
- fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
- if( rec->r.key.keyflags & KEYF_CHECKED ) {
- if( rec->r.key.keyflags & KEYF_VALID )
- fputs(", valid", fp );
- if( rec->r.key.keyflags & KEYF_EXPIRED )
- fputs(", expired", fp );
- if( rec->r.key.keyflags & KEYF_REVOKED )
- fputs(", revoked", fp );
- }
- putc('\n', fp);
- break;
- case RECTYPE_UID:
- fprintf(fp, "uid %lu, next=%lu, pref=%lu, sig=%lu, hash=%02X%02X",
- rec->r.uid.lid,
- rec->r.uid.next,
- rec->r.uid.prefrec,
- rec->r.uid.siglist,
- rec->r.uid.namehash[18], rec->r.uid.namehash[19]);
- fprintf( fp, ", v=%02x", rec->r.uid.validity );
- if( rec->r.uid.uidflags & UIDF_CHECKED ) {
- if( rec->r.uid.uidflags & UIDF_VALID )
- fputs(", valid", fp );
- if( rec->r.uid.uidflags & UIDF_REVOKED )
- fputs(", revoked", fp );
- }
- putc('\n', fp);
- break;
- case RECTYPE_PREF:
- fprintf(fp, "pref %lu, next=%lu,",
- rec->r.pref.lid, rec->r.pref.next);
- for(i=0,p=rec->r.pref.data; i < ITEMS_PER_PREF_RECORD; i+=2,p+=2 ) {
- if( *p )
- fprintf(fp, " %c%d", *p == PREFTYPE_SYM ? 'S' :
- *p == PREFTYPE_HASH ? 'H' :
- *p == PREFTYPE_ZIP ? 'Z' : '?', p[1]);
- }
- putc('\n', fp);
- break;
- case RECTYPE_SIG:
- fprintf(fp, "sig %lu, next=%lu,",
- rec->r.sig.lid, rec->r.sig.next );
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( rec->r.sig.sig[i].lid ) {
- fprintf(fp, " %lu:", rec->r.sig.sig[i].lid );
- if( rec->r.sig.sig[i].flag & SIGF_CHECKED ) {
- fprintf(fp,"%c%c%c",
- (rec->r.sig.sig[i].flag & SIGF_VALID) ? 'V':
- (rec->r.sig.sig[i].flag & SIGF_IGNORED) ? 'I':'-',
- (rec->r.sig.sig[i].flag & SIGF_EXPIRED) ? 'E':'-',
- (rec->r.sig.sig[i].flag & SIGF_REVOKED) ? 'R':'-');
- }
- else if( rec->r.sig.sig[i].flag & SIGF_NOPUBKEY)
- fputs("?--", fp);
- else
- fputs("---", fp);
- }
- }
- putc('\n', fp);
- break;
- case RECTYPE_SDIR:
- fprintf(fp, "sdir %lu, keyid=%08lX%08lX, algo=%d, hint=%lu\n",
- rec->r.sdir.lid,
- (ulong)rec->r.sdir.keyid[0],
- (ulong)rec->r.sdir.keyid[1],
- rec->r.sdir.pubkey_algo,
- (ulong)rec->r.sdir.hintlist );
- break;
- case RECTYPE_CACH:
- fprintf(fp, "cach\n");
- break;
case RECTYPE_HTBL:
fprintf(fp, "htbl,");
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
@@ -1224,6 +1072,20 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
putc('\n', fp);
break;
+ case RECTYPE_TRUST:
+ fprintf(fp, "trust ");
+ for(i=0; i < 20; i++ )
+ fprintf(fp, "%02X", rec->r.trust.fingerprint[i] );
+ fprintf (fp, ", ot=%d, d=%d, vl=%lu\n", rec->r.trust.ownertrust,
+ rec->r.trust.depth, rec->r.trust.validlist);
+ break;
+ case RECTYPE_VALID:
+ fprintf(fp, "valid ");
+ for(i=0; i < 20; i++ )
+ fprintf(fp, "%02X", rec->r.valid.namehash[i] );
+ fprintf (fp, ", v=%d, next=%lu\n", rec->r.valid.validity,
+ rec->r.valid.next);
+ break;
default:
fprintf(fp, "unknown type %d\n", rec->rectype );
break;
@@ -1279,24 +1141,25 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
log_error( _("%s: not a trustdb file\n"), db_name );
rc = G10ERR_TRUSTDB;
}
- p += 2; /* skip "pgp" */
+ p += 2; /* skip "gpg" */
rec->r.ver.version = *p++;
rec->r.ver.marginals = *p++;
rec->r.ver.completes = *p++;
rec->r.ver.cert_depth = *p++;
p += 4; /* lock flags */
rec->r.ver.created = buftoulong(p); p += 4;
- rec->r.ver.mod_down = buftoulong(p); p += 4;
- rec->r.ver.mod_up = buftoulong(p); p += 4;
- rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
+ rec->r.ver.nextcheck = buftoulong(p); p += 4;
+ p += 4;
+ p += 4;
rec->r.ver.firstfree =buftoulong(p); p += 4;
- rec->r.ver.sdirhashtbl =buftoulong(p); p += 4;
+ p += 4;
+ rec->r.ver.trusthashtbl =buftoulong(p); p += 4;
if( recnum ) {
log_error( _("%s: version record with recnum %lu\n"), db_name,
(ulong)recnum );
rc = G10ERR_TRUSTDB;
}
- else if( rec->r.ver.version != 2 ) {
+ else if( rec->r.ver.version != 3 ) {
log_error( _("%s: invalid file version %d\n"), db_name,
rec->r.ver.version );
rc = G10ERR_TRUSTDB;
@@ -1305,95 +1168,6 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
case RECTYPE_FREE:
rec->r.free.next = buftoulong(p); p += 4;
break;
- case RECTYPE_DIR: /*directory record */
- rec->r.dir.lid = buftoulong(p); p += 4;
- rec->r.dir.keylist = buftoulong(p); p += 4;
- rec->r.dir.uidlist = buftoulong(p); p += 4;
- rec->r.dir.cacherec = buftoulong(p); p += 4;
- rec->r.dir.ownertrust = *p++;
- rec->r.dir.dirflags = *p++;
- rec->r.dir.validity = *p++;
- rec->r.dir.valcheck = buftoulong(p); p += 4;
- rec->r.dir.checkat = buftoulong(p); p += 4;
- switch( rec->r.dir.validity ) {
- case 0:
- case TRUST_UNDEFINED:
- case TRUST_NEVER:
- case TRUST_MARGINAL:
- case TRUST_FULLY:
- case TRUST_ULTIMATE:
- break;
- default:
- log_info("lid %lu: invalid validity value - cleared\n", recnum);
- }
- if( rec->r.dir.lid != recnum ) {
- log_error( "%s: dir LID != recnum (%lu,%lu)\n",
- db_name, rec->r.dir.lid, (ulong)recnum );
- rc = G10ERR_TRUSTDB;
- }
- break;
- case RECTYPE_KEY: /* public key record */
- rec->r.key.lid = buftoulong(p); p += 4;
- rec->r.key.next = buftoulong(p); p += 4;
- p += 7;
- rec->r.key.keyflags = *p++;
- rec->r.key.pubkey_algo = *p++;
- rec->r.key.fingerprint_len = *p++;
- if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
- rec->r.key.fingerprint_len = 20;
- memcpy( rec->r.key.fingerprint, p, 20);
- break;
- case RECTYPE_UID: /* user id record */
- rec->r.uid.lid = buftoulong(p); p += 4;
- rec->r.uid.next = buftoulong(p); p += 4;
- rec->r.uid.prefrec = buftoulong(p); p += 4;
- rec->r.uid.siglist = buftoulong(p); p += 4;
- rec->r.uid.uidflags = *p++;
- rec->r.uid.validity = *p++;
- switch( rec->r.uid.validity ) {
- case 0:
- case TRUST_UNDEFINED:
- case TRUST_NEVER:
- case TRUST_MARGINAL:
- case TRUST_FULLY:
- case TRUST_ULTIMATE:
- break;
- default:
- log_info("lid %lu: invalid validity value - cleared\n", recnum);
- }
- memcpy( rec->r.uid.namehash, p, 20);
- break;
- case RECTYPE_PREF: /* preference record */
- rec->r.pref.lid = buftoulong(p); p += 4;
- rec->r.pref.next = buftoulong(p); p += 4;
- memcpy( rec->r.pref.data, p, 30 );
- break;
- case RECTYPE_SIG:
- rec->r.sig.lid = buftoulong(p); p += 4;
- rec->r.sig.next = buftoulong(p); p += 4;
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- rec->r.sig.sig[i].lid = buftoulong(p); p += 4;
- rec->r.sig.sig[i].flag = *p++;
- }
- break;
- case RECTYPE_SDIR: /* shadow directory record */
- rec->r.sdir.lid = buftoulong(p); p += 4;
- rec->r.sdir.keyid[0]= buftou32(p); p += 4;
- rec->r.sdir.keyid[1]= buftou32(p); p += 4;
- rec->r.sdir.pubkey_algo = *p++;
- p += 3;
- rec->r.sdir.hintlist = buftoulong(p);
- if( rec->r.sdir.lid != recnum ) {
- log_error( "%s: sdir LID != recnum (%lu,%lu)\n",
- db_name, rec->r.sdir.lid, (ulong)recnum );
- rc = G10ERR_TRUSTDB;
- }
- break;
- case RECTYPE_CACH: /* cache record */
- rec->r.cache.lid = buftoulong(p); p += 4;
- memcpy(rec->r.cache.blockhash, p, 20); p += 20;
- rec->r.cache.trustlevel = *p++;
- break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
rec->r.htbl.item[i] = buftoulong(p); p += 4;
@@ -1405,6 +1179,18 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
}
break;
+ case RECTYPE_TRUST:
+ memcpy( rec->r.trust.fingerprint, p, 20); p+=20;
+ rec->r.trust.ownertrust = *p++;
+ rec->r.trust.depth = *p++;
+ p += 2;
+ rec->r.trust.validlist = buftoulong(p); p += 4;
+ break;
+ case RECTYPE_VALID:
+ memcpy( rec->r.valid.namehash, p, 20); p+=20;
+ rec->r.valid.validity = *p++;
+ rec->r.valid.next = buftoulong(p); p += 4;
+ break;
default:
log_error( "%s: invalid record type %d at recnum %lu\n",
db_name, rec->rectype, (ulong)recnum );
@@ -1445,79 +1231,18 @@ tdbio_write_record( TRUSTREC *rec )
*p++ = rec->r.ver.cert_depth;
p += 4; /* skip lock flags */
ulongtobuf(p, rec->r.ver.created); p += 4;
- ulongtobuf(p, rec->r.ver.mod_down); p += 4;
- ulongtobuf(p, rec->r.ver.mod_up); p += 4;
- ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
+ ulongtobuf(p, rec->r.ver.nextcheck); p += 4;
+ p += 4;
+ p += 4;
ulongtobuf(p, rec->r.ver.firstfree ); p += 4;
- ulongtobuf(p, rec->r.ver.sdirhashtbl ); p += 4;
+ p += 4;
+ ulongtobuf(p, rec->r.ver.trusthashtbl ); p += 4;
break;
case RECTYPE_FREE:
ulongtobuf(p, rec->r.free.next); p += 4;
break;
- case RECTYPE_DIR: /*directory record */
- ulongtobuf(p, rec->r.dir.lid); p += 4;
- ulongtobuf(p, rec->r.dir.keylist); p += 4;
- ulongtobuf(p, rec->r.dir.uidlist); p += 4;
- ulongtobuf(p, rec->r.dir.cacherec); p += 4;
- *p++ = rec->r.dir.ownertrust;
- *p++ = rec->r.dir.dirflags;
- *p++ = rec->r.dir.validity;
- ulongtobuf(p, rec->r.dir.valcheck); p += 4;
- ulongtobuf(p, rec->r.dir.checkat); p += 4;
- assert( rec->r.dir.lid == recnum );
- break;
-
- case RECTYPE_KEY:
- ulongtobuf(p, rec->r.key.lid); p += 4;
- ulongtobuf(p, rec->r.key.next); p += 4;
- p += 7;
- *p++ = rec->r.key.keyflags;
- *p++ = rec->r.key.pubkey_algo;
- *p++ = rec->r.key.fingerprint_len;
- memcpy( p, rec->r.key.fingerprint, 20); p += 20;
- break;
-
- case RECTYPE_UID: /* user id record */
- ulongtobuf(p, rec->r.uid.lid); p += 4;
- ulongtobuf(p, rec->r.uid.next); p += 4;
- ulongtobuf(p, rec->r.uid.prefrec); p += 4;
- ulongtobuf(p, rec->r.uid.siglist); p += 4;
- *p++ = rec->r.uid.uidflags;
- *p++ = rec->r.uid.validity;
- memcpy( p, rec->r.uid.namehash, 20 ); p += 20;
- break;
-
- case RECTYPE_PREF:
- ulongtobuf(p, rec->r.pref.lid); p += 4;
- ulongtobuf(p, rec->r.pref.next); p += 4;
- memcpy( p, rec->r.pref.data, 30 );
- break;
-
- case RECTYPE_SIG:
- ulongtobuf(p, rec->r.sig.lid); p += 4;
- ulongtobuf(p, rec->r.sig.next); p += 4;
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- ulongtobuf(p, rec->r.sig.sig[i].lid); p += 4;
- *p++ = rec->r.sig.sig[i].flag;
- }
- break;
-
- case RECTYPE_SDIR:
- ulongtobuf( p, rec->r.sdir.lid); p += 4;
- u32tobuf( p, rec->r.sdir.keyid[0] ); p += 4;
- u32tobuf( p, rec->r.sdir.keyid[1] ); p += 4;
- *p++ = rec->r.sdir.pubkey_algo;
- p += 3;
- ulongtobuf( p, rec->r.sdir.hintlist );
- break;
-
- case RECTYPE_CACH:
- ulongtobuf(p, rec->r.cache.lid); p += 4;
- memcpy(p, rec->r.cache.blockhash, 20); p += 20;
- *p++ = rec->r.cache.trustlevel;
- break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
@@ -1532,6 +1257,20 @@ tdbio_write_record( TRUSTREC *rec )
}
break;
+ case RECTYPE_TRUST:
+ memcpy( p, rec->r.trust.fingerprint, 20); p += 20;
+ *p++ = rec->r.trust.ownertrust;
+ *p++ = rec->r.trust.depth;
+ p += 2;
+ ulongtobuf( p, rec->r.trust.validlist); p += 4;
+ break;
+
+ case RECTYPE_VALID:
+ memcpy( p, rec->r.valid.namehash, 20); p += 20;
+ *p++ = rec->r.valid.validity;
+ ulongtobuf( p, rec->r.valid.next); p += 4;
+ break;
+
default:
BUG();
}
@@ -1539,10 +1278,8 @@ tdbio_write_record( TRUSTREC *rec )
rc = put_record_into_cache( recnum, buf );
if( rc )
;
- else if( rec->rectype == RECTYPE_KEY )
- rc = update_keyhashtbl( rec );
- else if( rec->rectype == RECTYPE_SDIR )
- rc = update_sdirhashtbl( rec );
+ else if( rec->rectype == RECTYPE_TRUST )
+ rc = update_trusthashtbl( rec );
return rc;
}
@@ -1557,10 +1294,10 @@ tdbio_delete_record( ulong recnum )
rc = tdbio_read_record( recnum, &rec, 0 );
if( rc )
;
- else if( rec.rectype == RECTYPE_KEY )
- rc = drop_from_keyhashtbl( &rec );
- else if( rec.rectype == RECTYPE_SDIR )
- rc = drop_from_sdirhashtbl( &rec );
+ else if( rec.rectype == RECTYPE_TRUST ) {
+ rc = drop_from_hashtable( get_trusthashrec(),
+ rec.r.trust.fingerprint, 20, rec.recnum );
+ }
if( rc )
return rc;
@@ -1657,104 +1394,38 @@ tdbio_new_recnum()
-/****************
- * Search the trustdb for a key which matches PK and return the dir record
- * The local_id of PK is set to the correct value
- */
-int
-tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec )
-{
- byte fingerprint[MAX_FINGERPRINT_LEN];
- size_t fingerlen;
- u32 keyid[2];
- int rc;
-
- keyid_from_pk( pk, keyid );
- fingerprint_from_pk( pk, fingerprint, &fingerlen );
- rc = tdbio_search_dir_byfpr( fingerprint, fingerlen,
- pk->pubkey_algo, rec );
-
- if( !rc ) {
- if( pk->local_id && pk->local_id != rec->recnum )
- log_error("%s: found record, but LID from memory does "
- "not match recnum (%lu,%lu)\n",
- db_name, pk->local_id, rec->recnum );
- pk->local_id = rec->recnum;
- }
- return rc;
-}
-
-
static int
-cmp_krec_fpr( void *dataptr, const TRUSTREC *rec )
+cmp_trec_fpr ( void *fpr, const TRUSTREC *rec )
{
- const struct cmp_krec_fpr_struct *d = dataptr;
-
- return rec->rectype == RECTYPE_KEY
- && ( !d->pubkey_algo || rec->r.key.pubkey_algo == d->pubkey_algo )
- && rec->r.key.fingerprint_len == d->fprlen
- && !memcmp( rec->r.key.fingerprint, d->fpr, d->fprlen );
+ return rec->rectype == RECTYPE_TRUST
+ && !memcmp( rec->r.trust.fingerprint, fpr, 20);
}
+
int
-tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
- int pubkey_algo, TRUSTREC *rec )
+tdbio_search_trust_byfpr( const byte *fingerprint, TRUSTREC *rec )
{
- struct cmp_krec_fpr_struct cmpdata;
- ulong recnum;
int rc;
- assert( fingerlen == 20 || fingerlen == 16 );
-
- /* locate the key using the hash table */
- cmpdata.pubkey_algo = pubkey_algo;
- cmpdata.fpr = fingerprint;
- cmpdata.fprlen = fingerlen;
- rc = lookup_hashtable( get_keyhashrec(), fingerprint, fingerlen,
- cmp_krec_fpr, &cmpdata, rec );
- if( !rc ) {
- recnum = rec->r.key.lid;
- /* Now read the dir record */
- rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
- if( rc )
- log_error("%s: can't read dirrec %lu: %s\n",
- db_name, recnum, g10_errstr(rc) );
- }
+ /* locate the trust record using the hash table */
+ rc = lookup_hashtable( get_trusthashrec(), fingerprint, 20,
+ cmp_trec_fpr, (void*)fingerprint, rec );
return rc;
}
-
-
-static int
-cmp_sdir( void *dataptr, const TRUSTREC *rec )
+int
+tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec)
{
- const struct cmp_xdir_struct *d = dataptr;
+ byte fingerprint[MAX_FINGERPRINT_LEN];
+ size_t fingerlen;
- return rec->rectype == RECTYPE_SDIR
- && ( !d->pubkey_algo || rec->r.sdir.pubkey_algo == d->pubkey_algo )
- && rec->r.sdir.keyid[0] == d->keyid[0]
- && rec->r.sdir.keyid[1] == d->keyid[1];
+ fingerprint_from_pk( pk, fingerprint, &fingerlen );
+ for (; fingerlen < 20; fingerlen++ )
+ fingerprint[fingerlen] = 0;
+ return tdbio_search_trust_byfpr (fingerprint, rec);
}
-int
-tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec )
-{
- struct cmp_xdir_struct cmpdata;
- int rc;
- byte key[8];
-
- /* locate the shadow dir record using the hash table */
- u32tobuf( key , keyid[0] );
- u32tobuf( key+4 , keyid[1] );
- cmpdata.pubkey_algo = pubkey_algo;
- cmpdata.keyid[0] = keyid[0];
- cmpdata.keyid[1] = keyid[1];
- rc = lookup_hashtable( get_sdirhashrec(), key, 8,
- cmp_sdir, &cmpdata, rec );
- return rc;
-}
-
void
tdbio_invalid(void)
@@ -1764,4 +1435,130 @@ tdbio_invalid(void)
g10_exit(2);
}
+/*
+ * Migrate the trustdb as just up to gpg 1.0.6 (trustdb version 2)
+ * to the 2.1 version as used with 1.0.6b - This is pretty trivial as needs
+ * only to scan the tdb and insert new the new trust records. The old ones are
+ * obsolte from now on
+ */
+static void
+migrate_from_v2 ()
+{
+ TRUSTREC rec;
+ int i, n;
+ struct {
+ ulong keyrecno;
+ byte ot;
+ byte okay;
+ byte fpr[20];
+ } *ottable;
+ int ottable_size, ottable_used;
+ byte oldbuf[40];
+ ulong recno;
+ int count;
+
+ ottable_size = 5;
+ ottable = m_alloc (ottable_size * sizeof *ottable);
+ ottable_used = 0;
+
+ /* We have some restrictions here. We can't use the version record
+ * and we can't use any of the old hashtables because we dropped the
+ * code. So we first collect all ownertrusts and then use a second
+ * pass fo find the associated keys. We have to do this all without using
+ * the regular record read functions.
+ */
+
+ /* get all the ownertrusts */
+ if (lseek (db_fd, 0, SEEK_SET ) == -1 )
+ log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno));
+ for (recno=0;;recno++)
+ {
+ do
+ n = read (db_fd, oldbuf, 40);
+ while (n==-1 && errno == EINTR);
+ if (!n)
+ break; /* eof */
+ if (n != 40)
+ log_fatal ("migrate_vfrom_v2: read error or short read\n");
+
+ if (*oldbuf != 2)
+ continue;
+
+ /* v2 dir record */
+ if (ottable_used == ottable_size)
+ {
+ ottable_size += 1000;
+ ottable = m_realloc (ottable, ottable_size * sizeof *ottable);
+ }
+ ottable[ottable_used].keyrecno = buftoulong (oldbuf+6);
+ ottable[ottable_used].ot = oldbuf[17];
+ ottable[ottable_used].okay = 0;
+ memset (ottable[ottable_used].fpr,0, 20);
+ if (ottable[ottable_used].keyrecno)
+ ottable_used++;
+ }
+ log_info ("found %d ownertrust records\n", ottable_used);
+
+ /* Read again and find the fingerprints */
+ if (lseek (db_fd, 0, SEEK_SET ) == -1 )
+ log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno));
+ for (recno=0;;recno++)
+ {
+ do
+ n = read (db_fd, oldbuf, 40);
+ while (n==-1 && errno == EINTR);
+ if (!n)
+ break; /* eof */
+ if (n != 40)
+ log_fatal ("migrate_from_v2: read error or short read\n");
+
+ if (*oldbuf != 3)
+ continue;
+
+ /* v2 key record */
+ for (i=0; i < ottable_used; i++)
+ {
+ if (ottable[i].keyrecno == recno)
+ {
+ memcpy (ottable[i].fpr, oldbuf+20, 20);
+ ottable[i].okay = 1;
+ break;
+ }
+ }
+ }
+
+ /* got everything - create the v3 trustdb */
+ if (ftruncate (db_fd, 0))
+ log_fatal ("can't truncate `%s': %s\n", db_name, strerror (errno) );
+ if (create_version_record ())
+ log_fatal ("failed to recreate version record of `%s'\n", db_name);
+
+ /* access the hash table, so it is store just after the version record,
+ * this is not needed put a dump is more pretty */
+ get_trusthashrec ();
+
+ /* And insert the old ownertrust values */
+ count = 0;
+ for (i=0; i < ottable_used; i++)
+ {
+ if (!ottable[i].okay)
+ continue;
+
+ memset (&rec, 0, sizeof rec);
+ rec.recnum = tdbio_new_recnum ();
+ rec.rectype = RECTYPE_TRUST;
+ memcpy(rec.r.trust.fingerprint, ottable[i].fpr, 20);
+ rec.r.trust.ownertrust = ottable[i].ot;
+ if (tdbio_write_record (&rec))
+ log_fatal ("failed to write trust record of `%s'\n", db_name);
+ count++;
+ }
+
+ revalidation_mark ();
+ tdbio_sync ();
+ log_info ("migrated %d version 2 ownertrusts\n", count);
+ m_free (ottable);
+}
+
+
diff --git a/g10/tdbio.h b/g10/tdbio.h
index d615ac687..f1148240a 100644
--- a/g10/tdbio.h
+++ b/g10/tdbio.h
@@ -35,41 +35,13 @@
#define RECTYPE_VER 1
-#define RECTYPE_DIR 2
-#define RECTYPE_KEY 3
-#define RECTYPE_UID 4
-#define RECTYPE_PREF 5
-#define RECTYPE_SIG 6
-#define RECTYPE_SDIR 8
-#define RECTYPE_CACH 9
#define RECTYPE_HTBL 10
#define RECTYPE_HLST 11
+#define RECTYPE_TRUST 12
+#define RECTYPE_VALID 13
#define RECTYPE_FREE 254
-#define DIRF_CHECKED 1 /* has been checked - bits 1,2,3 are valid */
-#define DIRF_VALID 2 /* This key is valid: There is at least */
- /* one uid with a selfsignature or an revocation */
-#define DIRF_EXPIRED 4 /* the complete key has expired */
-#define DIRF_REVOKED 8 /* the complete key has been revoked */
-#define DIRF_NEWKEYS 128 /* new keys are available: we can check the sigs */
-
-#define KEYF_CHECKED 1 /* This key has been checked */
-#define KEYF_VALID 2 /* This is a valid (sub)key */
-#define KEYF_EXPIRED 4 /* this key is expired */
-#define KEYF_REVOKED 8 /* this key has been revoked */
-
-#define UIDF_CHECKED 1 /* user id has been checked - other bits are valid */
-#define UIDF_VALID 2 /* this is a valid user id */
-#define UIDF_REVOKED 8 /* this user id has been revoked */
-
-#define SIGF_CHECKED 1 /* signature has been checked - bits 0..6 are valid */
-#define SIGF_VALID 2 /* the signature is valid */
-#define SIGF_EXPIRED 4 /* the key of this signature has expired */
-#define SIGF_REVOKED 8 /* this signature has been revoked */
-#define SIGF_IGNORED 64 /* this signature is ignored by the system */
-#define SIGF_NOPUBKEY 128 /* there is no pubkey for this sig */
-
struct trust_record {
int rectype;
int mark;
@@ -78,73 +50,21 @@ struct trust_record {
ulong recnum;
union {
struct { /* version record: */
- byte version; /* should be 2 */
+ byte version; /* should be 3 */
byte marginals;
byte completes;
byte cert_depth;
ulong created; /* timestamp of trustdb creation */
- ulong mod_down; /* timestamp of last modification downward */
- ulong mod_up; /* timestamp of last modification upward */
- ulong keyhashtbl;
+ ulong nextcheck; /* timestamp of next scheduled check */
+ ulong reserved;
+ ulong reserved2;
ulong firstfree;
- ulong sdirhashtbl;
+ ulong reserved3;
+ ulong trusthashtbl;
} ver;
struct { /* free record */
ulong next;
} free;
- struct { /* directory record */
- ulong lid;
- ulong keylist; /* List of keys (the first is the primary key)*/
- ulong uidlist; /* list of uid records */
- ulong cacherec; /* the cache record */
- byte ownertrust;
- byte dirflags;
- byte validity; /* calculated trustlevel over all uids */
- ulong valcheck; /* timestamp of last validation check */
- ulong checkat; /* Check key when this time has been reached*/
- } dir;
- struct { /* primary public key record */
- ulong lid;
- ulong next; /* next key */
- byte keyflags;
- byte pubkey_algo;
- byte fingerprint_len;
- byte fingerprint[20];
- } key;
- struct { /* user id reord */
- ulong lid; /* point back to the directory record */
- ulong next; /* points to next user id record */
- ulong prefrec; /* recno of preference record */
- ulong siglist; /* list of valid signatures (w/o self-sig)*/
- byte uidflags;
- byte validity; /* calculated trustlevel of this uid */
- byte namehash[20]; /* ripemd hash of the username */
- } uid;
- struct { /* preference record */
- ulong lid; /* point back to the directory record */
- /* or 0 for a global pref record */
- ulong next; /* points to next pref record */
- byte data[ITEMS_PER_PREF_RECORD];
- } pref; /* pref records are not anymore used! */
- struct { /* signature record */
- ulong lid;
- ulong next; /* recnno of next record or NULL for last one */
- struct {
- ulong lid; /* of pubkey record of signator (0=unused) */
- byte flag; /* SIGF_xxxxx */
- } sig[SIGS_PER_RECORD];
- } sig;
- struct {
- ulong lid;
- u32 keyid[2];
- byte pubkey_algo;
- u32 hintlist;
- } sdir;
- struct { /* cache record */
- ulong lid;
- byte blockhash[20];
- byte trustlevel; /* calculated trustlevel */
- } cache;
struct {
ulong item[ITEMS_PER_HTBL_RECORD];
} htbl;
@@ -152,25 +72,21 @@ struct trust_record {
ulong next;
ulong rnum[ITEMS_PER_HLST_RECORD]; /* of another record */
} hlst;
+ struct {
+ byte fingerprint[20];
+ byte ownertrust;
+ byte depth;
+ ulong validlist;
+ } trust;
+ struct {
+ byte namehash[20];
+ ulong next;
+ byte validity;
+ } valid;
} r;
};
typedef struct trust_record TRUSTREC;
-typedef struct {
- ulong lid; /* localid */
- ulong sigrec;
- ulong sig_lid; /* returned signatures LID */
- unsigned sig_flag; /* returned signature record flag */
- struct { /* internal data */
- int init_done;
- int eof;
- TRUSTREC rec;
- ulong nextuid;
- int index;
- } ctl;
-} SIGREC_CONTEXT;
-
-
/*-- tdbio.c --*/
int tdbio_set_dbname( const char *new_dbname, int create );
const char *tdbio_get_dbname(void);
@@ -178,8 +94,8 @@ void tdbio_dump_record( TRUSTREC *rec, FILE *fp );
int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
int tdbio_write_record( TRUSTREC *rec );
int tdbio_db_matches_options(void);
-ulong tdbio_read_modify_stamp( int modify_down );
-void tdbio_write_modify_stamp( int up, int down );
+ulong tdbio_read_nextcheck (void);
+void tdbio_write_nextcheck (ulong stamp);
int tdbio_is_dirty(void);
int tdbio_sync(void);
int tdbio_begin_transaction(void);
@@ -187,11 +103,8 @@ int tdbio_end_transaction(void);
int tdbio_cancel_transaction(void);
int tdbio_delete_record( ulong recnum );
ulong tdbio_new_recnum(void);
-int tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec );
-int tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
- int pubkey_algo, TRUSTREC *rec );
-int tdbio_search_dir( u32 *keyid, int pubkey_algo, TRUSTREC *rec );
-int tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec );
+int tdbio_search_trust_byfpr(const byte *fingerprint, TRUSTREC *rec );
+int tdbio_search_trust_bypk(PKT_public_key *pk, TRUSTREC *rec );
void tdbio_invalid(void);
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 55368be65..9ed3a2860 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -22,596 +22,355 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-#include <ctype.h>
#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
-#include "trustdb.h"
#include "options.h"
#include "packet.h"
#include "main.h"
#include "i18n.h"
#include "tdbio.h"
-#include "ttyio.h"
+#include "trustdb.h"
-#if MAX_FINGERPRINT_LEN > 20
- #error Must change structure of trustdb
-#endif
-struct keyid_list {
- struct keyid_list *next;
- u32 keyid[2];
-};
-
-struct local_id_item {
- struct local_id_item *next;
- ulong lid;
- unsigned flag;
-};
-
-struct local_id_table {
- struct local_id_table *next; /* only used to keep a list of unused tables */
- struct local_id_item *items[16];
+/*
+ * A structure to store key identification as well as some stuff needed
+ * for validation
+ */
+struct key_item {
+ struct key_item *next;
+ unsigned int ownertrust;
+ u32 kid[2];
};
-typedef struct local_id_table *LOCAL_ID_TABLE;
-
-
-struct enum_cert_paths_ctx {
- int init;
- int idx;
-};
-
+typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
-struct recno_list_struct {
- struct recno_list_struct *next;
- ulong recno;
- int type;
-};
-typedef struct recno_list_struct *RECNO_LIST;
-
-
-
-typedef struct trust_node *TN;
-struct trust_node {
- TN back; /* parent */
- TN list; /* list of other node (should all be of the same type)*/
- TN next; /* used to build the list */
- int is_uid; /* set if this is an uid node */
- ulong lid; /* key or uid recordnumber */
- union {
- struct {
- int ownertrust;
- int validity;
- /* helper */
- int buckstop;
- } k;
- struct {
- int marginal_count;
- int fully_count;
- int validity;
- } u;
- } n;
+/*
+ * Structure to keep track of keys, this is used as an array wherre
+ * the item right after the last one has a keyblock set to NULL.
+ * Maybe we can drop this thing and replace it by key_item
+ */
+struct key_array {
+ KBNODE keyblock;
};
-static TN used_tns;
-static int alloced_tns;
-static int max_alloced_tns;
-
-static struct keyid_list *trusted_key_list;
-
-static LOCAL_ID_TABLE new_lid_table(void);
-static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
-static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
-
-
-static int propagate_validity( TN root, TN node,
- int (*add_fnc)(ulong), unsigned *retflgs );
-
-static void print_user_id( FILE *fp, const char *text, u32 *keyid );
-static int do_check( TRUSTREC *drec, unsigned *trustlevel,
- const char *nhash, int (*add_fnc)(ulong),
- unsigned *retflgs);
-static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
-static int do_update_trust_record( KBNODE keyblock, TRUSTREC *drec,
- int sigs_only, int *modified );
-static int check_trust_record( TRUSTREC *drec, int sigs_only );
-static void mark_fresh_keys(void);
-
-/* a table used to keep track of ultimately trusted keys
- * which are the ones from our secrings and the trusted keys */
-static LOCAL_ID_TABLE ultikey_table;
-
-
-/* a table to keep track of newly importted keys. This one is
- * create by the insert_trust_record function and from time to time
- * used to verify key signature which have been done with these new keys */
-static LOCAL_ID_TABLE fresh_imported_keys;
-static int fresh_imported_keys_count;
-#define FRESH_KEY_CHECK_THRESHOLD 200
-
-/* list of unused lid items and tables */
-static LOCAL_ID_TABLE unused_lid_tables;
-static struct local_id_item *unused_lid_items;
-
+/* control information for the trust DB */
static struct {
int init;
int level;
char *dbname;
} trustdb_args;
-
-/**********************************************
- *********** record read write **************
- **********************************************/
-
-
-/****************
- * Read a record but die if it does not exist
- */
-static void
-read_record( ulong recno, TRUSTREC *rec, int rectype )
-{
- int rc = tdbio_read_record( recno, rec, rectype );
- if( !rc )
- return;
- log_error(_("trust record %lu, req type %d: read failed: %s\n"),
- recno, rectype, g10_errstr(rc) );
- tdbio_invalid();
-}
-
+/* some globals */
+static struct key_item *user_utk_list; /* temp. used to store --trusted-keys */
+static struct key_item *utk_list; /* all ultimately trusted keys */
-/****************
- * Wirte a record but die on error
- */
-static void
-write_record( TRUSTREC *rec )
-{
- int rc = tdbio_write_record( rec );
- if( !rc )
- return;
- log_error(_("trust record %lu, type %d: write failed: %s\n"),
- rec->recnum, rec->rectype, g10_errstr(rc) );
- tdbio_invalid();
-}
-
-/****************
- * Delete a record but die on error
- */
-static void
-delete_record( ulong recno )
-{
- int rc = tdbio_delete_record( recno );
- if( !rc )
- return;
- log_error(_("trust record %lu: delete failed: %s\n"),
- recno, g10_errstr(rc) );
- tdbio_invalid();
-}
+/* Keep track on whether we did an update trustDB already */
+static int did_nextcheck;
-/****************
- * sync the db
- */
-static void
-do_sync(void)
-{
- int rc = tdbio_sync();
- if( !rc )
- return;
- log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
- g10_exit(2);
-}
+static int validate_keys (int interactive);
/**********************************************
- ***************** helpers ******************
+ ************* some helpers *******************
**********************************************/
-
-static LOCAL_ID_TABLE
-new_lid_table(void)
+static struct key_item *
+new_key_item (void)
{
- LOCAL_ID_TABLE a;
-
- a = unused_lid_tables;
- if( a ) {
- unused_lid_tables = a->next;
- memset( a, 0, sizeof *a );
- }
- else
- a = m_alloc_clear( sizeof *a );
- return a;
+ struct key_item *k;
+
+ k = m_alloc_clear (sizeof *k);
+ return k;
}
-#if 0
static void
-release_lid_table( LOCAL_ID_TABLE tbl )
+release_key_items (struct key_item *k)
{
- struct local_id_item *a, *a2;
- int i;
-
- for(i=0; i < 16; i++ ) {
- for(a=tbl->items[i]; a; a = a2 ) {
- a2 = a->next;
- a->next = unused_lid_items;
- unused_lid_items = a;
- }
- }
- tbl->next = unused_lid_tables;
- unused_lid_tables = tbl;
-}
-#endif
+ struct key_item *k2;
-
-/****************
- * Remove all items from a LID table
- */
-static void
-clear_lid_table( LOCAL_ID_TABLE tbl )
-{
- struct local_id_item *a, *a2;
- int i;
-
- for(i=0; i < 16; i++ ) {
- for(a=tbl->items[i]; a; a = a2 ) {
- a2 = a->next;
- a->next = unused_lid_items;
- unused_lid_items = a;
- }
- tbl->items[i] = NULL;
+ for (; k; k = k2)
+ {
+ k2 = k->next;
+ m_free (k);
}
}
-
-/****************
- * Add a new item to the table or return 1 if we already have this item
+/*
+ * For fast keylook up we need a hash table. Each byte of a KeyIDs
+ * should be distributed equally over the 256 possible values (except
+ * for v3 keyIDs but we consider them as not important here). So we
+ * can just use one byte to index a table of 256 key items.
+ * Possible optimization: Don not use key_items but other hash_table when the
+ * duplicates lists gets too large.
*/
-static int
-ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag )
+static KeyHashTable
+new_key_hash_table (void)
{
- struct local_id_item *a;
-
- for( a = tbl->items[lid & 0x0f]; a; a = a->next )
- if( a->lid == lid )
- return 1;
- a = unused_lid_items;
- if( a )
- unused_lid_items = a->next;
- else
- a = m_alloc( sizeof *a );
- a->lid = lid;
- a->flag = flag;
- a->next = tbl->items[lid & 0x0f];
- tbl->items[lid & 0x0f] = a;
- return 0;
+ struct key_item **tbl;
+
+ tbl = m_alloc_clear (256 * sizeof *tbl);
+ return tbl;
}
-static int
-qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag )
+static void
+release_key_hash_table (KeyHashTable tbl)
{
- struct local_id_item *a;
-
- for( a = tbl->items[lid & 0x0f]; a; a = a->next )
- if( a->lid == lid ) {
- if( flag )
- *flag = a->flag;
- return 0;
- }
- return -1;
-}
+ int i;
+ if (!tbl)
+ return;
+ for (i=0; i < 256; i++)
+ release_key_items (tbl[i]);
+ m_free (tbl);
+}
-static TN
-new_tn(void)
+/*
+ * Returns: True if the keyID is in the given hash table
+ */
+static int
+test_key_hash_table (KeyHashTable tbl, u32 *kid)
{
- TN t;
+ struct key_item *k;
- if( used_tns ) {
- t = used_tns;
- used_tns = t->next;
- memset( t, 0, sizeof *t );
- }
- else
- t = m_alloc_clear( sizeof *t );
- if( ++alloced_tns > max_alloced_tns )
- max_alloced_tns = alloced_tns;
- return t;
+ for (k = tbl[(kid[1] & 0xff)]; k; k = k->next)
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ return 1;
+ return 0;
}
-
+/*
+ * Add a new key to the hash table. The key is indetified by its key ID.
+ */
static void
-release_tn( TN t )
+add_key_hash_table (KeyHashTable tbl, u32 *kid)
{
- if( t ) {
- t->next = used_tns;
- used_tns = t;
- alloced_tns--;
- }
+ struct key_item *k, *kk;
+
+ for (k = tbl[(kid[1] & 0xff)]; k; k = k->next)
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ return; /* already in table */
+
+ kk = new_key_item ();
+ kk->kid[0] = kid[0];
+ kk->kid[1] = kid[1];
+ kk->next = tbl[(kid[1] & 0xff)];
+ tbl[(kid[1] & 0xff)] = kk;
}
+/*
+ * Release a key_array
+ */
static void
-release_tn_tree( TN kr )
+release_key_array ( struct key_array *keys )
{
- TN kr2;
+ struct key_array *k;
- for( ; kr; kr = kr2 ) {
- release_tn_tree( kr->list );
- kr2 = kr->next;
- release_tn( kr );
+ if (keys) {
+ for (k=keys; k->keyblock; k++)
+ release_kbnode (k->keyblock);
+ m_free (keys);
}
}
+
+/*********************************************
+ ********** Initialization *****************
+ *********************************************/
-
-/**********************************************
- ****** access by LID and other helpers *******
- **********************************************/
-/****************
- * Return the keyid from the primary key identified by LID.
+/*
+ * Used to register extra ultimately trusted keys - this has to be done
+ * before initializing the validation module.
+ * FIXME: Should be replaced by a function to add those keys to the trustdb.
*/
-int
-keyid_from_lid( ulong lid, u32 *keyid )
+void
+register_trusted_key( const char *string )
{
- TRUSTREC rec;
- int rc;
-
- init_trustdb();
- keyid[0] = keyid[1] = 0;
- rc = tdbio_read_record( lid, &rec, 0 );
- if( rc ) {
- log_error(_("error reading dir record for LID %lu: %s\n"),
- lid, g10_errstr(rc));
- return G10ERR_TRUSTDB;
- }
- if( rec.rectype == RECTYPE_SDIR )
- return 0;
- if( rec.rectype != RECTYPE_DIR ) {
- log_error(_("lid %lu: expected dir record, got type %d\n"),
- lid, rec.rectype );
- return G10ERR_TRUSTDB;
- }
- if( !rec.r.dir.keylist ) {
- log_error(_("no primary key for LID %lu\n"), lid );
- return G10ERR_TRUSTDB;
- }
- rc = tdbio_read_record( rec.r.dir.keylist, &rec, RECTYPE_KEY );
- if( rc ) {
- log_error(_("error reading primary key for LID %lu: %s\n"),
- lid, g10_errstr(rc));
- return G10ERR_TRUSTDB;
- }
- keyid_from_fingerprint( rec.r.key.fingerprint, rec.r.key.fingerprint_len,
- keyid );
-
- return 0;
-}
+ KEYDB_SEARCH_DESC desc;
+ struct key_item *k;
+ if (classify_user_id (string, &desc) != KEYDB_SEARCH_MODE_LONG_KID ) {
+ log_error(_("`%s' is not a valid long keyID\n"), string );
+ return;
+ }
-ulong
-lid_from_keyblock( KBNODE keyblock )
-{
- KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
- PKT_public_key *pk;
- if( !node )
- BUG();
- pk = node->pkt->pkt.public_key;
- if( !pk->local_id ) {
- TRUSTREC rec;
- init_trustdb();
-
- get_dir_record( pk, &rec );
- }
- return pk->local_id;
+ k = new_key_item ();
+ k->kid[0] = desc.u.kid[0];
+ k->kid[1] = desc.u.kid[1];
+ k->next = user_utk_list;
+ user_utk_list = k;
}
-
+/*
+ * Helper to add a key to the global list of ultimately trusted keys.
+ * Retruns: true = inserted, false = already in in list.
+ */
static int
-get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
+add_utk (u32 *kid)
{
- int rc=0;
+ struct key_item *k;
- if( pk->local_id ) {
- read_record( pk->local_id, rec, RECTYPE_DIR );
- }
- else { /* no local_id: scan the trustdb */
- if( (rc=tdbio_search_dir_bypk( pk, rec )) && rc != -1 )
- log_error(_("get_dir_record: search_record failed: %s\n"),
- g10_errstr(rc));
+ for (k = utk_list; k; k = k->next)
+ {
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ {
+ return 0;
+ }
}
- return rc;
-}
-static ulong
-lid_from_keyid_no_sdir( u32 *keyid )
-{
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
- TRUSTREC rec;
- ulong lid = 0;
- int rc;
-
- rc = get_pubkey( pk, keyid );
- if( !rc ) {
- if( pk->local_id )
- lid = pk->local_id;
- else {
- rc = tdbio_search_dir_bypk( pk, &rec );
- if( !rc )
- lid = rec.recnum;
- }
- }
- free_public_key( pk );
- return lid;
+ k = new_key_item ();
+ k->kid[0] = kid[0];
+ k->kid[1] = kid[1];
+ k->ownertrust = TRUST_ULTIMATE;
+ k->next = utk_list;
+ utk_list = k;
+ if( opt.verbose > 1 )
+ log_info(_("key %08lX: accepted as trusted key\n"), (ulong)kid[1]);
+ return 1;
}
-
-/***********************************************
- ************* Initialization ****************
- ***********************************************/
-
-void
-register_trusted_key( const char *string )
+/****************
+ * Verify that all our secret keys are usable and put them into the utk_list.
+ */
+static void
+verify_own_keys(void)
{
- KEYDB_SEARCH_DESC desc;
- struct keyid_list *r;
-
- if (classify_user_id (string, &desc) != KEYDB_SEARCH_MODE_LONG_KID ) {
- log_error(_("`%s' is not a valid long keyID\n"), string );
- return;
- }
-
- for( r = trusted_key_list; r; r = r->next )
- if( r->keyid[0] == desc.u.kid[0] && r->keyid[1] == desc.u.kid[1] )
- return;
- r = m_alloc( sizeof *r );
- r->keyid[0] = desc.u.kid[0];
- r->keyid[1] = desc.u.kid[1];
- r->next = trusted_key_list;
- trusted_key_list = r;
-}
+ TRUSTREC rec;
+ ulong recnum;
+ int rc;
+ struct key_item *k;
+ int hint_shown = 0;
+ if (utk_list)
+ return;
-static void
-add_ultimate_key( PKT_public_key *pk, u32 *keyid )
-{
- int rc;
-
- /* first make sure that the pubkey is in the trustdb */
- rc = query_trust_record( pk );
- if( rc == -1 && opt.dry_run )
- return;
- if( rc == -1 ) { /* put it into the trustdb */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error(_("key %08lX: can't put it into the trustdb\n"),
- (ulong)keyid[1] );
- return;
+ /* scan the trustdb to find all ultimately trusted keys */
+ for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ )
+ {
+ if ( rec.rectype == RECTYPE_TRUST
+ && (rec.r.trust.ownertrust & TRUST_MASK) == TRUST_ULTIMATE)
+ {
+ byte *fpr = rec.r.trust.fingerprint;
+ int fprlen;
+ u32 kid[2];
+
+ /* Problem: We do only use fingerprints in the trustdb but
+ * we need the keyID here to indetify the key; we can only
+ * use that ugly hack to distinguish between 16 and 20
+ * butes fpr - it does not work always so we better change
+ * the whole validation code to only work with
+ * fingerprints */
+ fprlen = (!fpr[16] && !fpr[17] && !fpr[18] && !fpr[19])? 16:20;
+ keyid_from_fingerprint (fpr, fprlen, kid);
+ if (!add_utk (kid))
+ log_info(_("key %08lX occurs more than once in the trustdb\n"),
+ (ulong)kid[1]);
}
}
- else if( rc ) {
- log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
- return;
+
+ /* the --trusted-key option is again deprecated; however we automagically
+ * add those keys to the trustdb */
+ for (k = user_utk_list; k; k = k->next)
+ {
+ if ( add_utk (k->kid) )
+ { /* not yet in trustDB as ultimately trusted */
+ PKT_public_key pk;
+
+ memset (&pk, 0, sizeof pk);
+ rc = get_pubkey (&pk, k->kid);
+ if (rc) {
+ log_info(_("key %08lX: no public key for trusted key - skipped\n"),
+ (ulong)k->kid[1] );
+ }
+ else {
+ update_ownertrust (&pk,
+ ((get_ownertrust (&pk) & ~TRUST_MASK)
+ | TRUST_ULTIMATE ));
+ release_public_key_parts (&pk);
+ }
+ if (!hint_shown)
+ {
+ log_info ("the --trusted-key option is now obsolete; "
+ "use the --edit command instead.\n");
+ log_info ("given keys will be marked as trusted\n");
+ hint_shown = 1;
+ }
+ log_info ("key %08lX marked as ultimately trusted\n",
+ (ulong)k->kid[1]);
+ }
}
- if( DBG_TRUST )
- log_debug("key %08lX.%lu: stored into ultikey_table\n",
- (ulong)keyid[1], pk->local_id );
-
- if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
- log_info(_("key %08lX: already in trusted key table\n"),
- (ulong)keyid[1]);
- else if( opt.verbose > 1 )
- log_info(_("key %08lX: accepted as trusted key.\n"),
- (ulong)keyid[1]);
+ /* release the helper table table */
+ release_key_items (user_utk_list);
+ user_utk_list = NULL;
+ return;
}
-/****************
- * Verify that all our public keys are in the trustdb.
+
+/*********************************************
+ *********** TrustDB stuff *******************
+ *********************************************/
+
+/*
+ * Read a record but die if it does not exist
*/
-static int
-verify_own_keys(void)
+static void
+read_record (ulong recno, TRUSTREC *rec, int rectype )
{
- int rc;
- void *enum_context = NULL;
- PKT_secret_key *sk = m_alloc_clear( sizeof *sk );
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
- u32 keyid[2];
- struct keyid_list *kl;
-
-
- /* put the trusted keys into the ultikey table */
- for( kl = trusted_key_list; kl; kl = kl->next ) {
- keyid[0] = kl->keyid[0];
- keyid[1] = kl->keyid[1];
- /* get the public key */
- memset( pk, 0, sizeof *pk );
- rc = get_pubkey( pk, keyid );
- if( rc ) {
- log_info(_("key %08lX: no public key for trusted key - skipped\n"),
- (ulong)keyid[1] );
- }
- else {
- add_ultimate_key( pk, keyid );
- release_public_key_parts( pk );
- }
+ int rc = tdbio_read_record (recno, rec, rectype);
+ if (rc)
+ {
+ log_error(_("trust record %lu, req type %d: read failed: %s\n"),
+ recno, rec->rectype, g10_errstr(rc) );
+ tdbio_invalid();
+ }
+ if (rectype != rec->rectype)
+ {
+ log_error(_("trust record %lu is not of requested type %d\n"),
+ rec->recnum, rectype);
+ tdbio_invalid();
}
+}
- /* And now add all secret keys to the ultikey table */
- while( !(rc=enum_secret_keys( &enum_context, sk, 0 ) ) ) {
- int have_pk = 0;
-
- keyid_from_sk( sk, keyid );
-
- if( DBG_TRUST )
- log_debug("key %08lX: checking secret key\n", (ulong)keyid[1] );
-
- if( !opt.quiet && is_secret_key_protected( sk ) < 1 )
- log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
- (ulong)keyid[1] );
-
- for( kl = trusted_key_list; kl; kl = kl->next ) {
- if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
- goto skip; /* already in trusted key table */
- }
-
- /* see whether we can access the public key of this secret key */
- memset( pk, 0, sizeof *pk );
- rc = get_pubkey( pk, keyid );
- if( rc ) {
- if (!opt.quiet)
- log_info(_("key %08lX: secret key without public key "
- "- skipped\n"), (ulong)keyid[1] );
- goto skip;
- }
- have_pk=1;
-
- if( cmp_public_secret_key( pk, sk ) ) {
- log_info(_("key %08lX: secret and public key don't match\n"),
- (ulong)keyid[1] );
- goto skip;
- }
-
- add_ultimate_key( pk, keyid );
-
- skip:
- release_secret_key_parts( sk );
- if( have_pk )
- release_public_key_parts( pk );
- }
- if( rc != -1 )
- log_error(_("enumerate secret keys failed: %s\n"), g10_errstr(rc) );
- else
- rc = 0;
-
- /* release the trusted keyid table */
- { struct keyid_list *kl2;
- for( kl = trusted_key_list; kl; kl = kl2 ) {
- kl2 = kl->next;
- m_free( kl );
- }
- trusted_key_list = NULL;
+/*
+ * Write a record and die on error
+ */
+static void
+write_record (TRUSTREC *rec)
+{
+ int rc = tdbio_write_record (rec);
+ if (rc)
+ {
+ log_error(_("trust record %lu, type %d: write failed: %s\n"),
+ rec->recnum, rec->rectype, g10_errstr(rc) );
+ tdbio_invalid();
}
+}
- enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
- free_secret_key( sk );
- free_public_key( pk );
- return rc;
+/*
+ * sync the TrustDb and die on error
+ */
+static void
+do_sync(void)
+{
+ int rc = tdbio_sync ();
+ if(rc)
+ {
+ log_error (_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
+ g10_exit(2);
+ }
}
@@ -634,1846 +393,353 @@ setup_trustdb( int level, const char *dbname )
void
init_trustdb()
{
- int rc=0;
- int level = trustdb_args.level;
- const char* dbname = trustdb_args.dbname;
+ int rc=0;
+ int level = trustdb_args.level;
+ const char* dbname = trustdb_args.dbname;
- if( trustdb_args.init )
- return;
-
- trustdb_args.init = 1;
-
- if( !ultikey_table )
- ultikey_table = new_lid_table();
-
- if( !level || level==1 ) {
- rc = tdbio_set_dbname( dbname, !!level );
- if( !rc ) {
- if( !level )
- return;
+ if( trustdb_args.init )
+ return;
- /* verify that our own keys are in the trustDB
- * or move them to the trustdb. */
- rc = verify_own_keys();
+ trustdb_args.init = 1;
- /* should we check whether there is no other ultimately trusted
- * key in the database? */
- }
+ if ( !level || level==1)
+ {
+ rc = tdbio_set_dbname( dbname, !!level );
+ if( !rc )
+ {
+ if( !level )
+ return;
+
+ /* verify that our own keys are in the trustDB
+ * or move them to the trustdb. */
+ verify_own_keys();
+
+ /* should we check whether there is no other ultimately trusted
+ * key in the database? */
+ }
}
- else
- BUG();
- if( rc )
- log_fatal("can't init trustdb: %s\n", g10_errstr(rc) );
+ else
+ BUG();
+ if( rc )
+ log_fatal("can't init trustdb: %s\n", g10_errstr(rc) );
}
-/****************
- * This function should be called in certain cases to sync the internal state
- * of the trustdb with the file image. Currently it is needed after
- * a sequence of insert_trust_record() calls.
- */
-void
-sync_trustdb()
-{
- if( fresh_imported_keys && fresh_imported_keys_count )
- mark_fresh_keys();
-}
-
-
/***********************************************
************* Print helpers ****************
***********************************************/
-static void
-print_user_id( FILE *fp, const char *text, u32 *keyid )
-{
- char *p;
- size_t n;
-
- p = get_user_id( keyid, &n );
- if( fp ) {
- fprintf( fp, "%s \"", text );
- print_utf8_string( fp, p, n );
- putc('\"', fp);
- putc('\n', fp);
- }
- else {
- tty_printf( "%s \"", text );
- tty_print_utf8_string( p, n );
- tty_printf( "\"\n" );
- }
- m_free(p);
-}
-
-
/****************
* This function returns a letter for a trustvalue Trust flags
* are ignore.
*/
int
-trust_letter( unsigned value )
-{
- switch( (value & TRUST_MASK) ) {
- case TRUST_UNKNOWN: return '-';
- case TRUST_EXPIRED: return 'e';
- case TRUST_UNDEFINED: return 'q';
- case TRUST_NEVER: return 'n';
- case TRUST_MARGINAL: return 'm';
- case TRUST_FULLY: return 'f';
- case TRUST_ULTIMATE: return 'u';
- default: return 0 ;
- }
-}
-
-
-#if 0
-static void
-print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
-{
- int rc, c, i;
- u32 keyid[2];
- char *p;
- size_t n;
-
- for( i = 0; i < pathlen; i++ ) {
- if( highlight )
- fputs(highlight == path[i].lid? "* ":" ", fp );
- rc = keyid_from_lid( path[i].lid, keyid );
- if( rc )
- fprintf(fp, "????????.%lu:", path[i].lid );
- else
- fprintf(fp,"%08lX.%lu:", (ulong)keyid[1], path[i].lid );
- c = trust_letter(path[i].otrust);
- if( c )
- putc( c, fp );
- else
- fprintf( fp, "%02x", path[i].otrust );
- putc('/', fp);
- c = trust_letter(path[i].trust);
- if( c )
- putc( c, fp );
- else
- fprintf( fp, "%02x", path[i].trust );
- putc(' ', fp);
- p = get_user_id( keyid, &n );
- putc(' ', fp);
- putc('\"', fp);
- print_utf8_string( fp, p, n > 40? 40:n );
- putc('\"', fp);
- m_free(p);
- putc('\n', fp );
- }
-}
-#endif
-
-
-static void
-print_default_uid( FILE *fp, ulong lid )
-{
- u32 keyid[2];
-
- if( !keyid_from_lid( lid, keyid ) )
- print_user_id( fp, "", keyid );
-}
-
-
-static void
-print_uid_from_keyblock( FILE *fp, KBNODE keyblock, ulong urecno )
-{
- TRUSTREC urec;
- KBNODE node;
- byte uhash[20];
-
- read_record( urecno, &urec, RECTYPE_UID );
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID ) {
- PKT_user_id *uidpkt = node->pkt->pkt.user_id;
-
- if( uidpkt->photo )
- rmd160_hash_buffer( uhash, uidpkt->photo, uidpkt->photolen );
- else
- rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
- if( !memcmp( uhash, urec.r.uid.namehash, 20 ) ) {
- print_string( fp, uidpkt->name, uidpkt->len, ':' );
- return;
- }
- }
- }
-
- fputs("[?]", fp );
-}
-
-
-
-static void
-dump_tn_tree( FILE *fp, int level, TN tree )
-{
- TN kr, ur;
-
- for( kr=tree; kr; kr = kr->next ) {
- if( fp ) {
- fprintf( fp, "%*s", level*4, "" );
- fprintf( fp, "K%lu(ot=%d,val=%d) ", kr->lid,
- kr->n.k.ownertrust,
- kr->n.k.validity );
- }
- else {
- tty_printf("%*s", level*4, "" );
- tty_printf("K%lu(ot=%d,val=%d) ", kr->lid,
- kr->n.k.ownertrust,
- kr->n.k.validity );
- }
- print_default_uid( fp, kr->lid );
- for( ur=kr->list; ur; ur = ur->next ) {
- if( fp ) {
- fprintf(fp, "%*s ", level*4, "" );
- fprintf(fp, "U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
- ur->n.u.marginal_count,
- ur->n.u.fully_count,
- ur->n.u.validity
- );
- }
- else {
- tty_printf("%*s ", level*4, "" );
- tty_printf("U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
- ur->n.u.marginal_count,
- ur->n.u.fully_count,
- ur->n.u.validity
- );
- }
- dump_tn_tree( fp, level+1, ur->list );
- }
- }
-}
-
-/****************
- * Special version of dump_tn_tree, which prints it colon delimited.
- * Format:
- * level:keyid:type:recno:ot:val:mc:cc:name:
- * With TYPE = U for a user ID
- * K for a key
- * The RECNO is either the one of the dir record or the one of the uid record.
- * OT is the the usual trust letter and only availabel on K lines.
- * VAL is the calcualted validity
- * MC is the marginal trust counter and only available on U lines
- * CC is the same for the complete count
- * NAME ist the username and only printed on U lines
- */
-static void
-dump_tn_tree_with_colons( int level, TN tree )
-{
- TN kr, ur;
-
- for( kr=tree; kr; kr = kr->next ) {
- KBNODE kb = NULL;
- u32 kid[2];
-
- keyid_from_lid( kr->lid, kid );
- get_keyblock_bylid( &kb, kr->lid );
-
- printf( "%d:%08lX%08lX:K:%lu:%c:%c::::\n",
- level, (ulong)kid[0], (ulong)kid[1], kr->lid,
- trust_letter( kr->n.k.ownertrust ),
- trust_letter( kr->n.k.validity ) );
- for( ur=kr->list; ur; ur = ur->next ) {
- printf( "%d:%08lX%08lX:U:%lu::%c:%d:%d:",
- level, (ulong)kid[0], (ulong)kid[1], ur->lid,
- trust_letter( kr->n.u.validity ),
- ur->n.u.marginal_count,
- ur->n.u.fully_count );
- print_uid_from_keyblock( stdout, kb, ur->lid );
- putchar(':');
- putchar('\n');
- dump_tn_tree_with_colons( level+1, ur->list );
- }
- release_kbnode( kb );
- }
-}
-
-
-
-/***********************************************
- ************* trustdb maintenance ***********
- ***********************************************/
-
-/****************
- * Create or update shadow dir record and return the LID of the record
- */
-static ulong
-create_shadow_dir( PKT_signature *sig )
-{
- TRUSTREC sdir;
- int rc;
-
- /* first see whether we already have such a record */
- rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir );
- if( rc && rc != -1 ) {
- log_error("tdbio_search_sdir failed: %s\n", g10_errstr(rc));
- tdbio_invalid();
- }
- if( rc == -1 ) { /* not found: create */
- memset( &sdir, 0, sizeof sdir );
- sdir.recnum = tdbio_new_recnum();
- sdir.rectype= RECTYPE_SDIR;
- sdir.r.sdir.lid = sdir.recnum;
- sdir.r.sdir.keyid[0] = sig->keyid[0];
- sdir.r.sdir.keyid[1] = sig->keyid[1];
- sdir.r.sdir.pubkey_algo = sig->pubkey_algo;
- write_record( &sdir );
- }
- return sdir.recnum;
-}
-
-
-static ulong
-find_or_create_lid( PKT_signature *sig )
-{
- ulong lid;
-
- lid = lid_from_keyid_no_sdir( sig->keyid );
- if( !lid )
- lid = create_shadow_dir( sig );
- return lid;
-}
-
-
-
-/****************
- * Check the validity of a key and calculate the keyflags
- * keynode points to
- * a node with a [sub]key. mainkid has the key ID of the primary key
- * keyblock is the complete keyblock which is needed for signature
- * checking. LID and PK is only used in verbose mode.
- */
-static unsigned int
-check_keybinding( KBNODE keyblock, KBNODE keynode, u32 *mainkid,
- ulong lid, PKT_public_key *pk )
-{
- KBNODE node;
- int keybind_seen = 0;
- int revoke_seen = 0;
- unsigned int keyflags=0;
- int is_main = (keynode->pkt->pkttype == PKT_PUBLIC_KEY);
- int rc;
-
- if( DBG_TRUST )
- log_debug("check_keybinding: %08lX.%lu\n",
- (ulong)mainkid[1], lid );
-
- if( is_main ) {
- /* a primary key is always valid (user IDs are handled elsewhere)*/
- keyflags = KEYF_CHECKED | KEYF_VALID;
- }
-
- for( node=keynode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
-
- sig = node->pkt->pkt.signature;
-
- if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures */
-
- if( sig->sig_class == 0x18 && !keybind_seen && !is_main ) {
- /* check until we find a valid keybinding */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_("key %08lX.%lu: Good subkey binding\n"),
- (ulong)keyid_from_pk(pk,NULL), lid );
- keyflags |= KEYF_CHECKED | KEYF_VALID;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid subkey binding: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
- keyflags |= KEYF_CHECKED;
- keyflags &= ~KEYF_VALID;
- }
- keybind_seen = 1;
- }
- else if( sig->sig_class == 0x20 && !revoke_seen ) {
- /* this is a key revocation certificate: check it */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_("key %08lX.%lu: Valid key revocation\n"),
- (ulong)keyid_from_pk(pk, NULL), lid );
- keyflags |= KEYF_REVOKED;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid key revocation: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
- }
- revoke_seen = 1;
- }
- else if( sig->sig_class == 0x28 && !revoke_seen && !is_main ) {
- /* this is a subkey revocation certificate: check it */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_(
- "key %08lX.%lu: Valid subkey revocation\n"),
- (ulong)keyid_from_pk(pk,NULL), lid );
- keyflags |= KEYF_REVOKED;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid subkey binding: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
- }
- revoke_seen = 1;
- }
- /* Hmmm: should we handle direct key signatures here? */
- }
-
- return keyflags;
-}
-
-
-static ulong
-make_key_records( KBNODE keyblock, ulong lid, u32 *keyid, int *mainrev )
-{
- TRUSTREC *krecs, **kend, *k, *k2;
- KBNODE node;
- PKT_public_key *pk;
- byte fpr[MAX_FINGERPRINT_LEN];
- size_t fprlen;
- ulong keyrecno;
-
- *mainrev = 0;
- krecs = NULL; kend = &krecs;
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype != PKT_PUBLIC_KEY
- && node->pkt->pkttype != PKT_PUBLIC_SUBKEY )
- continue;
- pk = node->pkt->pkt.public_key;
- fingerprint_from_pk( pk, fpr, &fprlen );
-
- /* create the key record */
- k = m_alloc_clear( sizeof *k );
- k->rectype = RECTYPE_KEY;
- k->r.key.lid = lid;
- k->r.key.pubkey_algo = pk->pubkey_algo;
- k->r.key.fingerprint_len = fprlen;
- memcpy(k->r.key.fingerprint, fpr, fprlen );
- k->recnum = tdbio_new_recnum();
- *kend = k;
- kend = &k->next;
-
- k->r.key.keyflags = check_keybinding( keyblock, node, keyid, lid, pk );
- if( (k->r.key.keyflags & KEYF_REVOKED)
- && node->pkt->pkttype == PKT_PUBLIC_KEY )
- *mainrev = 1;
- }
-
- keyrecno = krecs? krecs->recnum : 0;
- /* write the keylist and release the memory */
- for( k = krecs; k ; k = k2 ) {
- if( k->next )
- k->r.key.next = k->next->recnum;
- write_record( k );
- k2 = k->next;
- m_free( k );
- }
- return keyrecno;
-}
-
-
-/****************
- * Check the validity of a user ID and calculate the uidflags
- * keynode points to a node with a user ID.
- * mainkid has the key ID of the primary key, keyblock is the complete
- * keyblock which is needed for signature checking.
- * Returns: The uid flags and the self-signature which is considered to
- * be the most current.
- */
-static unsigned int
-check_uidsigs( KBNODE keyblock, KBNODE keynode, u32 *mainkid, ulong lid,
- PKT_signature **bestsig )
-{
- KBNODE node;
- unsigned int uidflags = 0;
- PKT_signature *sig;
- PKT_signature *selfsig = NULL; /* the latest valid self signature */
- int rc;
-
- if( DBG_TRUST ) {
- PKT_user_id *uid;
- log_debug("check_uidsigs: %08lX.%lu \"",
- (ulong)mainkid[1], lid );
- assert(keynode->pkt->pkttype == PKT_USER_ID );
- uid = keynode->pkt->pkt.user_id;
- print_string( log_stream(), uid->name, uid->len, '\"' );
- fputs("\"\n", log_stream());
- }
-
- /* first we check only the selfsignatures */
- for( node=keynode->next; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
- sig = node->pkt->pkt.signature;
- if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures for now */
-
- if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info( "uid %08lX.%lu: %s\n",
- (ulong)mainkid[1], lid, _("Good self-signature") );
- uidflags |= UIDF_CHECKED | UIDF_VALID;
- if( !selfsig )
- selfsig = sig; /* use the first valid sig */
- else if( sig->timestamp > selfsig->timestamp
- && sig->sig_class >= selfsig->sig_class )
- selfsig = sig; /* but this one is newer */
- }
- else {
- log_info( "uid %08lX: %s: %s\n",
- (ulong)mainkid[1], _("Invalid self-signature"),
- g10_errstr(rc) );
- uidflags |= UIDF_CHECKED;
- }
- }
- }
-
- /* and now check for revocations - we must do this after the
- * self signature check because a self-signature which is newer
- * than a revocation makes the revocation invalid.
- * RFC2440 is quiet about tis but I feel this is reasonable for
- * non-primary-key revocations. */
- for( node=keynode->next; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
- sig = node->pkt->pkt.signature;
- if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures for now */
-
- if( sig->sig_class == 0x30 ) { /* cert revocation */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) {
- log_info( "uid %08lX.%lu: %s\n",
- (ulong)mainkid[1], lid,
- _("Valid user ID revocation skipped "
- "due to a newer self signature") );
- }
- else if( !rc ) {
- if( opt.verbose )
- log_info( "uid %08lX.%lu: %s\n",
- (ulong)mainkid[1], lid, _("Valid user ID revocation") );
- uidflags |= UIDF_CHECKED | UIDF_VALID | UIDF_REVOKED;
- }
- else {
- log_info("uid %08lX: %s: %s\n",
- (ulong)mainkid[1], _("Invalid user ID revocation"),
- g10_errstr(rc) );
- }
- }
- }
-
- *bestsig = selfsig;
- return uidflags;
-}
-
-
-static unsigned int
-check_sig_record( KBNODE keyblock, KBNODE signode,
- ulong siglid, int sigidx, u32 *keyid, ulong lid,
- u32 *r_expiretime, int *mod_down, int *mod_up )
-{
- PKT_signature *sig = signode->pkt->pkt.signature;
- unsigned int sigflag = 0;
- TRUSTREC tmp;
- int revocation=0, expired=0, rc;
-
- if( DBG_TRUST )
- log_debug("check_sig_record: %08lX.%lu %lu[%d]\n",
- (ulong)keyid[1], lid, siglid, sigidx );
- *r_expiretime = 0;
- if( (sig->sig_class&~3) == 0x10 ) /* regular certification */
- ;
- else if( sig->sig_class == 0x30 ) /* cert revocation */
- revocation = 1;
- else
- return SIGF_CHECKED | SIGF_IGNORED;
-
- read_record( siglid, &tmp, 0 );
- if( tmp.rectype == RECTYPE_DIR ) {
- /* the public key is in the trustdb: check sig */
- rc = check_key_signature2( keyblock, signode, NULL,
- r_expiretime, &expired );
- if( !rc ) { /* valid signature */
- if( opt.verbose )
- log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s\n",
- (ulong)keyid[1], lid, siglid, sigidx,
- (ulong)sig->keyid[1],
- revocation? _("Valid certificate revocation")
- : _("Good certificate") );
- sigflag |= SIGF_CHECKED | SIGF_VALID;
- if( expired ) {
- sigflag |= SIGF_EXPIRED;
- /* We have to reset the expiretime, so that this signature
- * does not get checked over and over due to the reached
- * expiretime */
- *r_expiretime = 0;
- }
- if( revocation ) {
- sigflag |= SIGF_REVOKED;
- *mod_down = 1;
- }
- else
- *mod_up = 1;
- }
- else if( rc == G10ERR_NO_PUBKEY ) {
- /* This may happen if the key is still in the trustdb
- * but not available in the keystorage */
- sigflag |= SIGF_NOPUBKEY;
- *mod_down = 1;
- if( revocation )
- sigflag |= SIGF_REVOKED;
- }
- else {
- log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s: %s\n",
- (ulong)keyid[1], lid, siglid, sigidx,
- (ulong)sig->keyid[1],
- revocation? _("Invalid certificate revocation")
- : _("Invalid certificate"),
- g10_errstr(rc));
- sigflag |= SIGF_CHECKED;
- if( revocation ) {
- sigflag |= SIGF_REVOKED;
- *mod_down = 1;
- }
- }
- }
- else if( tmp.rectype == RECTYPE_SDIR ) {
- /* better check that it is the right one */
- if( tmp.r.sdir.keyid[0] == sig->keyid[0]
- && tmp.r.sdir.keyid[1] == sig->keyid[1]
- && (!tmp.r.sdir.pubkey_algo
- || tmp.r.sdir.pubkey_algo == sig->pubkey_algo ))
- sigflag |= SIGF_NOPUBKEY;
- else
- log_error(_("sig record %lu[%d] points to wrong record.\n"),
- siglid, sigidx );
- }
- else {
- log_error(_("sig record %lu[%d] points to wrong record.\n"),
- siglid, sigidx );
- tdbio_invalid();
- }
-
- return sigflag;
-}
-
-/****************
- * Make the sig records for the given uid record
- * We don't set flags here or even check the signatures; this will
- * happen latter.
- */
-static ulong
-make_sig_records( KBNODE keyblock, KBNODE uidnode,
- ulong lid, u32 *mainkid, u32 *min_expire,
- int *mod_down, int *mod_up )
-{
- TRUSTREC *srecs, **s_end, *s=NULL, *s2;
- KBNODE node;
- PKT_signature *sig;
- ulong sigrecno, siglid;
- int i, sigidx = 0;
- u32 expiretime;
-
- srecs = NULL; s_end = &srecs;
- for( node=uidnode->next; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
- sig = node->pkt->pkt.signature;
- if( mainkid[0] == sig->keyid[0] && mainkid[1] == sig->keyid[1] )
- continue; /* we don't care about self-signatures here */
-
- siglid = find_or_create_lid( sig );
- /* smash dups */
- /* FIXME: Here we have a problem:
- * We can't distinguish between a certification and a certification
- * revocation without looking at class of the signature - we have
- * to see how we can store the sigclass in the sigrecord..
- * Argg- I hope I can get rid of this ugly trustdb ASAP.
- */
- for( s2 = s; s2 ; s2 = s2->next ) {
- for(i=0; i < sigidx; i++ ) {
- if( s2->r.sig.sig[i].lid == siglid )
- goto leaveduptest;
- }
- }
- for( s2 = srecs; s2 ; s2 = s2->next ) {
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( s2->r.sig.sig[i].lid == siglid )
- goto leaveduptest;
- }
- }
- leaveduptest:
- if( s2 ) {
- log_info( "sig %08lX.%lu: %s\n", (ulong)mainkid[1], lid,
- _("duplicated certificate - deleted") );
- continue;
- }
-
- /* create the sig record */
- if( !sigidx ) {
- s = m_alloc_clear( sizeof *s );
- s->rectype = RECTYPE_SIG;
- s->r.sig.lid = lid;
- }
- s->r.sig.sig[sigidx].lid = siglid;
- s->r.sig.sig[sigidx].flag= check_sig_record( keyblock, node,
- siglid, sigidx,
- mainkid, lid, &expiretime,
- mod_down, mod_up );
-
- sigidx++;
- if( sigidx == SIGS_PER_RECORD ) {
- s->recnum = tdbio_new_recnum();
- *s_end = s;
- s_end = &s->next;
- sigidx = 0;
- }
- /* keep track of signers pk expire time */
- if( expiretime && (!*min_expire || *min_expire > expiretime ) )
- *min_expire = expiretime;
- }
- if( sigidx ) {
- s->recnum = tdbio_new_recnum();
- *s_end = s;
- s_end = &s->next;
- }
-
- sigrecno = srecs? srecs->recnum : 0;
- /* write the keylist and release the memory */
- for( s = srecs; s ; s = s2 ) {
- if( s->next )
- s->r.sig.next = s->next->recnum;
- write_record( s );
- s2 = s->next;
- m_free( s );
- }
- return sigrecno;
-}
-
-
-
-
-static ulong
-make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid, u32 *min_expire,
- int *mod_down, int *mod_up )
-{
- TRUSTREC *urecs, **uend, *u, *u2;
- KBNODE node;
- PKT_user_id *uid;
- byte uidhash[20];
- ulong uidrecno;
-
- urecs = NULL; uend = &urecs;
- for( node=keyblock; node; node = node->next ) {
- PKT_signature *bestsig;
-
- if( node->pkt->pkttype != PKT_USER_ID )
- continue;
- uid = node->pkt->pkt.user_id;
- if( uid->photo )
- rmd160_hash_buffer( uidhash, uid->photo, uid->photolen );
- else
- rmd160_hash_buffer( uidhash, uid->name, uid->len );
-
- /* create the uid record */
- u = m_alloc_clear( sizeof *u );
- u->rectype = RECTYPE_UID;
- u->r.uid.lid = lid;
- memcpy(u->r.uid.namehash, uidhash, 20 );
- u->recnum = tdbio_new_recnum();
- *uend = u;
- uend = &u->next;
-
- u->r.uid.uidflags = check_uidsigs( keyblock, node, keyid,
- lid, &bestsig );
- if( (u->r.uid.uidflags & UIDF_CHECKED)
- && (u->r.uid.uidflags & UIDF_VALID) ) {
- u->r.uid.prefrec = 0;
- }
-
- /* the next test is really bad because we should modify
- * out modification timestamps only if we really have a change.
- * But because we are deleting the uid records first it is somewhat
- * difficult to track those changes. fixme */
- if( !( u->r.uid.uidflags & UIDF_VALID )
- || ( u->r.uid.uidflags & UIDF_REVOKED ) )
- *mod_down=1;
- else
- *mod_up=1;
-
- /* create the list of signatures */
- u->r.uid.siglist = make_sig_records( keyblock, node,
- lid, keyid, min_expire,
- mod_down, mod_up );
- }
-
- uidrecno = urecs? urecs->recnum : 0;
- /* write the uidlist and release the memory */
- for( u = urecs; u ; u = u2 ) {
- if( u->next )
- u->r.uid.next = u->next->recnum;
- write_record( u );
- u2 = u->next;
- m_free( u );
- }
- return uidrecno;
-}
-
-
-
-/****************
- * Update all the info from the public keyblock.
- * The key must already exist in the keydb.
- */
-int
-update_trust_record( KBNODE keyblock, int recheck, int *modified )
-{
- TRUSTREC drec;
- int rc;
-
- /* NOTE: We don't need recheck anymore, but this might chnage again in
- * the future */
- if( opt.dry_run )
- return 0;
- if( modified )
- *modified = 0;
- init_trustdb();
- rc = get_dir_record( find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key, &drec );
- if( rc )
- return rc;
-
- rc = do_update_trust_record( keyblock, &drec, 0, modified );
- return rc;
-}
-
-/****************
- * Same as update_trust_record, but this functions expects the dir record.
- * On exit the dir record will reflect any changes made.
- * With sigs_only set only foreign key signatures are checked.
- */
-static int
-do_update_trust_record( KBNODE keyblock, TRUSTREC *drec,
- int sigs_only, int *modified )
-{
- PKT_public_key *primary_pk;
- TRUSTREC krec, urec, prec, helprec;
- int i, rc = 0;
- u32 keyid[2]; /* keyid of primary key */
- int mod_up = 0;
- int mod_down = 0;
- ulong recno, r2;
- u32 expiretime;
-
- primary_pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key;
- if( !primary_pk->local_id )
- primary_pk->local_id = drec->recnum;
-
- keyid_from_pk( primary_pk, keyid );
- if( DBG_TRUST )
- log_debug("do_update_trust_record: %08lX.%lu\n",
- (ulong)keyid[1], drec->recnum );
-
- rc = tdbio_begin_transaction();
- if( rc )
- return rc;
-
- /* delete the old stuff FIXME: implementend sigs_only */
- for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) {
- read_record( recno, &krec, RECTYPE_KEY );
- delete_record( recno );
- }
- drec->r.dir.keylist = 0;
- for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
- read_record( recno, &urec, RECTYPE_UID );
- for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) {
- /* we don't use preference records any more, but all ones might
- * still be there */
- read_record( r2, &prec, RECTYPE_PREF );
- delete_record( r2 );
- }
- for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) {
- read_record( r2, &helprec, RECTYPE_SIG );
- delete_record( r2 );
- }
- delete_record( recno );
- }
- drec->r.dir.uidlist = 0;
-
-
- /* insert new stuff */
- drec->r.dir.dirflags &= ~DIRF_REVOKED;
- drec->r.dir.dirflags &= ~DIRF_NEWKEYS;
- drec->r.dir.keylist = make_key_records( keyblock, drec->recnum, keyid, &i );
- if( i ) /* primary key has been revoked */
- drec->r.dir.dirflags |= DIRF_REVOKED;
- expiretime = 0;
- drec->r.dir.uidlist = make_uid_records( keyblock, drec->recnum, keyid,
- &expiretime, &mod_down, &mod_up );
- if( rc )
- rc = tdbio_cancel_transaction();
- else {
- if( modified && tdbio_is_dirty() )
- *modified = 1;
- drec->r.dir.dirflags |= DIRF_CHECKED;
- drec->r.dir.valcheck = 0;
- drec->r.dir.checkat = expiretime;
- write_record( drec );
- tdbio_write_modify_stamp( mod_up, mod_down );
- rc = tdbio_end_transaction();
- }
- return rc;
-}
-
-
-
-/****************
- * Insert a trust record into the TrustDB
- * This function assumes that the record does not yet exist.
- */
-int
-insert_trust_record( KBNODE keyblock )
+trust_letter (unsigned int value)
{
- TRUSTREC dirrec;
- TRUSTREC shadow;
- KBNODE node;
- int rc = 0;
- PKT_public_key *pk;
-
-
- if( opt.dry_run )
- return 0;
-
- init_trustdb();
-
- pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key;
- if( pk->local_id ) {
- log_debug("insert_trust_record with pk->local_id=%lu (2)\n",
- pk->local_id );
- rc = update_trust_record( keyblock, 1, NULL );
- return rc;
- }
-
- /* We have to look for a shadow dir record which must be reused
- * as the dir record. */
- rc = tdbio_search_sdir( pk->keyid, pk->pubkey_algo, &shadow );
- if( rc && rc != -1 ) {
- log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
- tdbio_invalid();
- }
- memset( &dirrec, 0, sizeof dirrec );
- dirrec.rectype = RECTYPE_DIR;
- if( !rc ) /* we have a shadow dir record - convert to dir record */
- dirrec.recnum = shadow.recnum;
- else
- dirrec.recnum = tdbio_new_recnum();
- dirrec.r.dir.lid = dirrec.recnum;
- write_record( &dirrec );
-
- /* put the LID into the keyblock */
- pk->local_id = dirrec.r.dir.lid;
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_PUBLIC_KEY
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- PKT_public_key *a_pk = node->pkt->pkt.public_key;
- a_pk->local_id = dirrec.r.dir.lid;
- }
- else if( node->pkt->pkttype == PKT_SIGNATURE ) {
- PKT_signature *a_sig = node->pkt->pkt.signature;
- a_sig->local_id = dirrec.r.dir.lid;
- }
+ switch( (value & TRUST_MASK) )
+ {
+ case TRUST_UNKNOWN: return '-';
+ case TRUST_EXPIRED: return 'e';
+ case TRUST_UNDEFINED: return 'q';
+ case TRUST_NEVER: return 'n';
+ case TRUST_MARGINAL: return 'm';
+ case TRUST_FULLY: return 'f';
+ case TRUST_ULTIMATE: return 'u';
+ default: return 0;
}
-
-
- /* mark tdb as modified upwards */
- tdbio_write_modify_stamp( 1, 0 );
-
- /* and put all the other stuff into the keydb */
- rc = do_update_trust_record( keyblock, &dirrec, 0, NULL );
-
- do_sync();
-
- /* keep track of new keys */
- if( !fresh_imported_keys )
- fresh_imported_keys = new_lid_table();
- ins_lid_table_item( fresh_imported_keys, pk->local_id, 0 );
- if( ++fresh_imported_keys_count > FRESH_KEY_CHECK_THRESHOLD )
- mark_fresh_keys();
-
- return rc;
}
-
-
/****************
- * Insert a trust record indentified by a PK into the TrustDB
+ * Recreate the WoT but do not ask for new ownertrusts
*/
-int
-insert_trust_record_by_pk( PKT_public_key *pk )
-{
- KBNODE keyblock = NULL;
- byte fingerprint[MAX_FINGERPRINT_LEN];
- size_t fingerlen;
- int rc;
-
- /* get the keyblock */
- fingerprint_from_pk( pk, fingerprint, &fingerlen );
- rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
- if( rc ) { /* that should never happen */
- log_debug( "insert_trust_record_by_pk: keyblock not found: %s\n",
- g10_errstr(rc) );
- }
- else {
- rc = insert_trust_record( keyblock );
- if( !rc ) /* copy the LID into the PK */
- pk->local_id = find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key->local_id;
- }
-
- release_kbnode( keyblock );
- return rc;
-}
-
-
-/****************
- * Check one trust record. This function is called for every
- * directory record which is to be checked. The supplied
- * dir record is modified according to the performed actions.
- * Currently we only do an update_trust_record.
- */
-static int
-check_trust_record( TRUSTREC *drec, int sigs_only )
+void
+check_trustdb()
{
- KBNODE keyblock;
- int modified, rc;
-
- rc = get_keyblock_bylid( &keyblock, drec->recnum );
- if( rc ) {
- log_debug( "check_trust_record %lu: keyblock not found: %s\n",
- drec->recnum, g10_errstr(rc) );
- return rc;
- }
-
- rc = do_update_trust_record( keyblock, drec, sigs_only, &modified );
- release_kbnode( keyblock );
-
- return rc;
+ init_trustdb();
+ validate_keys (0);
}
-/****************
- * Walk over the keyrings and create trustdb records for all keys
- * which are not currently in the trustdb.
- * It is intended to be used after a fast-import operation.
+/*
+ * Recreate the WoT.
*/
void
update_trustdb()
{
- KBNODE keyblock = NULL;
- KEYDB_HANDLE kdbhd;
- int rc;
-
- if( opt.dry_run )
- return;
-
- init_trustdb();
- kdbhd = keydb_new (0);
- rc = keydb_search_first (kdbhd);
- if (!rc) {
- ulong count=0, err_count=0, new_count=0;
-
- do {
- TRUSTREC drec;
- PKT_public_key *pk;
- /*int modified;*/
-
- rc = keydb_get_keyblock (kdbhd, &keyblock );
- if (rc)
- break;
-
- pk = find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt.public_key;
-
- rc = get_dir_record( pk, &drec );
- if( rc == -1 ) { /* not in trustdb: insert */
- rc = insert_trust_record( keyblock );
- if( rc && !pk->local_id ) {
- log_error(_("lid ?: insert failed: %s\n"),
- g10_errstr(rc) );
- err_count++;
- }
- else if( rc ) {
- log_error(_("lid %lu: insert failed: %s\n"),
- pk->local_id, g10_errstr(rc) );
- err_count++;
- }
- else {
- if( opt.verbose )
- log_info(_("lid %lu: inserted\n"), pk->local_id );
- new_count++;
- }
- }
- else if( rc ) {
- log_error(_("error reading dir record: %s\n"), g10_errstr(rc));
- err_count++;
- }
-
- release_kbnode( keyblock ); keyblock = NULL;
- if( !(++count % 100) )
- log_info(_("%lu keys so far processed\n"), count);
- } while ( !(rc = keydb_search_next (kdbhd)));
- log_info(_("%lu keys processed\n"), count);
- if( err_count )
- log_info(_("\t%lu keys with errors\n"), err_count);
- if( new_count )
- log_info(_("\t%lu keys inserted\n"), new_count);
- }
- if( rc && rc != -1 )
- log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
-
- keydb_release (kdbhd);
- release_kbnode( keyblock );
+ init_trustdb();
+ validate_keys (1);
}
-
-
-/****************
- * Do all required checks in the trustdb. This function walks over all
- * records in the trustdb and does scheduled processing.
- */
void
-check_trustdb( const char *username )
+revalidation_mark (void)
{
- TRUSTREC rec;
- ulong recnum;
- ulong count=0, upd_count=0, err_count=0, skip_count=0, sigonly_count=0;
- ulong current_time = make_timestamp();
-
- if( username )
- log_info("given user IDs ignored in check_trustdb\n");
-
- init_trustdb();
-
- for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- int sigs_only;
-
- if( rec.rectype != RECTYPE_DIR )
- continue; /* we only want the dir records */
-
- if( count && !(count % 100) && !opt.quiet )
- log_info(_("%lu keys so far processed\n"), count);
- count++;
- sigs_only = 0;
-
- if( !(rec.r.dir.dirflags & DIRF_CHECKED) )
- ;
- else if( !rec.r.dir.checkat || rec.r.dir.checkat > current_time ) {
- if( !(rec.r.dir.dirflags & DIRF_NEWKEYS) ) {
- skip_count++;
- continue; /* not scheduled for checking */
- }
- sigs_only = 1; /* new public keys - check them */
- sigonly_count++;
- }
-
- if( !rec.r.dir.keylist ) {
- log_info(_("lid %lu: dir record w/o key - skipped\n"), recnum);
- skip_count++;
- continue;
- }
-
- check_trust_record( &rec, sigs_only );
- }
-
- log_info(_("%lu keys processed\n"), count);
- if( sigonly_count )
- log_info(_("\t%lu due to new pubkeys\n"), sigonly_count);
- if( skip_count )
- log_info(_("\t%lu keys skipped\n"), skip_count);
- if( err_count )
- log_info(_("\t%lu keys with errors\n"), err_count);
- if( upd_count )
- log_info(_("\t%lu keys updated\n"), upd_count);
+ init_trustdb();
+ /* we simply set the time for the next check to 1 (far back in 1970)
+ * so that a --update-trustdb will be scheduled */
+ tdbio_write_nextcheck (1);
}
-
/***********************************************
- ********* Trust calculation *****************
+ *********** Ownertrust et al. ****************
***********************************************/
-/****************
- * Find all certification paths of a given LID.
- * Limit the search to MAX_DEPTH. stack is a helper variable which
- * should have been allocated with size max_depth, stack[0] should
- * be setup to the key we are investigating, so the minimal depth
- * we should ever see in this function is 1.
- * Returns: a new tree
- * certchain_set must be a valid set or point to NULL; this function
- * may modifiy it.
- *
- * Hmmm: add a fastscan mode which stops at valid validity nodes.
- */
-static TN
-build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
+static int
+read_trust_record (PKT_public_key *pk, TRUSTREC *rec)
{
- TRUSTREC dirrec;
- TRUSTREC uidrec;
- ulong uidrno;
- TN keynode;
-
- if( depth >= max_depth )
- return NULL;
-
- keynode = new_tn();
- if( !helproot )
- helproot = keynode;
- keynode->lid = lid;
- if( !qry_lid_table_flag( ultikey_table, lid, NULL ) ) {
- /* this is an ultimately trusted key;
- * which means that we have found the end of the chain:
- * We do this here prior to reading the dir record
- * because we don't really need the info from that record */
- keynode->n.k.ownertrust = TRUST_ULTIMATE;
- keynode->n.k.buckstop = 1;
- return keynode;
- }
- read_record( lid, &dirrec, 0 );
- if( dirrec.rectype != RECTYPE_DIR ) {
- if( dirrec.rectype != RECTYPE_SDIR )
- log_debug("lid %lu, has rectype %d"
- " - skipped\n", lid, dirrec.rectype );
- m_free(keynode);
- return NULL;
- }
-
- if( dirrec.r.dir.checkat && dirrec.r.dir.checkat <= make_timestamp() ) {
- check_trust_record( &dirrec, 0 );
- }
- else if( (dirrec.r.dir.dirflags & DIRF_NEWKEYS) ) {
- check_trust_record( &dirrec, 1 );
- }
-
- keynode->n.k.ownertrust = dirrec.r.dir.ownertrust & TRUST_MASK;
-
- /* loop over all user ids */
- for( uidrno = dirrec.r.dir.uidlist; uidrno; uidrno = uidrec.r.uid.next ) {
- TRUSTREC sigrec;
- ulong sigrno;
- TN uidnode = NULL;
-
- read_record( uidrno, &uidrec, RECTYPE_UID );
-
- if( !(uidrec.r.uid.uidflags & UIDF_CHECKED) )
- continue; /* user id has not been checked */
- if( !(uidrec.r.uid.uidflags & UIDF_VALID) )
- continue; /* user id is not valid */
- if( (uidrec.r.uid.uidflags & UIDF_REVOKED) )
- continue; /* user id has been revoked */
-
- /* loop over all signature records */
- for(sigrno=uidrec.r.uid.siglist; sigrno; sigrno = sigrec.r.sig.next ) {
- int i;
- TN tn;
-
- read_record( sigrno, &sigrec, RECTYPE_SIG );
-
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( !sigrec.r.sig.sig[i].lid )
- continue; /* skip deleted sigs */
- if( !(sigrec.r.sig.sig[i].flag & SIGF_CHECKED) )
- continue; /* skip unchecked signatures */
- if( !(sigrec.r.sig.sig[i].flag & SIGF_VALID) )
- continue; /* skip invalid signatures */
- if( (sigrec.r.sig.sig[i].flag & SIGF_EXPIRED) )
- continue; /* skip expired signatures */
- if( (sigrec.r.sig.sig[i].flag & SIGF_REVOKED) )
- continue; /* skip revoked signatures */
- /* check for cycles */
- for( tn=keynode; tn && tn->lid != sigrec.r.sig.sig[i].lid;
- tn = tn->back )
- ;
- if( tn )
- continue; /* cycle found */
-
- tn = build_cert_tree( sigrec.r.sig.sig[i].lid,
- depth+1, max_depth, helproot );
- if( !tn )
- continue; /* cert chain too deep or error */
-
- if( !uidnode ) {
- uidnode = new_tn();
- uidnode->back = keynode;
- uidnode->lid = uidrno;
- uidnode->is_uid = 1;
- uidnode->next = keynode->list;
- keynode->list = uidnode;
- }
-
- tn->back = uidnode;
- tn->next = uidnode->list;
- uidnode->list = tn;
- if( tn->n.k.buckstop ) {
- /* ultimately trusted key found:
- * no need to check more signatures of this uid */
- sigrec.r.sig.next = 0;
- break;
- }
- }
- } /* end loop over sig recs */
- } /* end loop over user ids */
-
- if( !keynode->list ) {
- release_tn_tree( keynode );
- keynode = NULL;
- }
-
- return keynode;
+ int rc;
+
+ init_trustdb();
+ rc = tdbio_search_trust_bypk (pk, rec);
+ if (rc == -1)
+ return -1; /* no record yet */
+ if (rc)
+ {
+ log_error ("trustdb: searching trust record failed: %s\n",
+ g10_errstr (rc));
+ return rc;
+ }
+
+ if (rec->rectype != RECTYPE_TRUST)
+ {
+ log_error ("trustdb: record %lu is not a trust record\n",
+ rec->recnum);
+ return G10ERR_TRUSTDB;
+ }
+
+ return 0;
}
-static void
-upd_one_ownertrust( ulong lid, unsigned new_trust, unsigned *retflgs )
-{
- TRUSTREC rec;
-
- read_record( lid, &rec, RECTYPE_DIR );
- if( DBG_TRUST )
- log_debug("upd_one_ownertrust of %lu from %u to %u\n",
- lid, (unsigned)rec.r.dir.ownertrust, new_trust );
- if( retflgs ) {
- if( (new_trust & TRUST_MASK) > (rec.r.dir.ownertrust & TRUST_MASK) )
- *retflgs |= 16; /* modified up */
- else
- *retflgs |= 32; /* modified down */
- }
-
- /* we preserve the disabled state here */
- if( (rec.r.dir.ownertrust & TRUST_FLAG_DISABLED) )
- rec.r.dir.ownertrust = new_trust | TRUST_FLAG_DISABLED;
- else
- rec.r.dir.ownertrust = new_trust & ~TRUST_FLAG_DISABLED;
- write_record( &rec );
-}
-
/****************
- * Update the ownertrust in the complete tree.
+ * Return the assigned ownertrust value for the given public key.
+ * The key should be the primary key.
*/
-static void
-propagate_ownertrust( TN kr, ulong lid, unsigned trust )
+unsigned int
+get_ownertrust ( PKT_public_key *pk)
{
- TN ur;
-
- for( ; kr; kr = kr->next ) {
- if( kr->lid == lid )
- kr->n.k.ownertrust = trust;
- for( ur=kr->list; ur; ur = ur->next )
- propagate_ownertrust( ur->list, lid, trust );
- }
+ TRUSTREC rec;
+ int rc;
+
+ rc = read_trust_record (pk, &rec);
+ if (rc == -1)
+ return TRUST_UNKNOWN; /* no record yet */
+ if (rc)
+ {
+ tdbio_invalid ();
+ return rc; /* actually never reached */
+ }
+
+ return rec.r.trust.ownertrust;
}
-/****************
- * Calculate the validity of all keys in the tree and especially
- * the one of the top key. If add_fnc is not NULL, it is used to
- * ask for missing ownertrust values (but only if this will help
- * us to increase the validity.
- * add_fnc is expected to take the LID of the key under question
- * and return a ownertrust value or an error: positive values
- * are assumed to be the new ownertrust value; a 0 does mean no change,
- * a -1 is a request to cancel this validation procedure, a -2 requests
- * a listing of the sub-tree using the tty functions.
- *
- *
- * Returns: 0 = okay
+/*
+ * Same as get_wonertrust byt return a trust letter
*/
-static int
-propagate_validity( TN root, TN node, int (*add_fnc)(ulong), unsigned *retflgs )
-{
- TN kr, ur;
- int max_validity = 0;
-
- assert( !node->is_uid );
- if( node->n.k.ownertrust == TRUST_ULTIMATE ) {
- /* this is one of our keys */
- assert( !node->list ); /* it should be a leaf */
- node->n.k.validity = TRUST_ULTIMATE;
- if( retflgs )
- *retflgs |= 1; /* found a path to an ultimately trusted key */
- return 0;
- }
-
- /* loop over all user ids */
- for( ur=node->list; ur && max_validity <= TRUST_FULLY; ur = ur->next ) {
- assert( ur->is_uid );
- /* loop over all signators */
- for(kr=ur->list; kr && max_validity <= TRUST_FULLY; kr = kr->next ) {
- if( propagate_validity( root, kr, add_fnc, retflgs ) )
- return -1; /* quit */
- if( kr->n.k.validity == TRUST_ULTIMATE ) {
- ur->n.u.fully_count = opt.completes_needed;
- }
- else if( kr->n.k.validity == TRUST_FULLY ) {
- if( add_fnc && !kr->n.k.ownertrust ) {
- int rc;
-
- if( retflgs )
- *retflgs |= 2; /* found key with undefined ownertrust*/
- do {
- rc = add_fnc( kr->lid );
- switch( rc ) {
- case TRUST_NEVER:
- case TRUST_MARGINAL:
- case TRUST_FULLY:
- propagate_ownertrust( root, kr->lid, rc );
- upd_one_ownertrust( kr->lid, rc, retflgs );
- if( retflgs )
- *retflgs |= 4; /* changed */
- break;
- case -1:
- return -1; /* cancel */
- case -2:
- dump_tn_tree( NULL, 0, kr );
- tty_printf("\n");
- break;
- default:
- break;
- }
- } while( rc == -2 );
- }
- if( kr->n.k.ownertrust == TRUST_FULLY )
- ur->n.u.fully_count++;
- else if( kr->n.k.ownertrust == TRUST_MARGINAL )
- ur->n.u.marginal_count++;
- }
-
- if( ur->n.u.fully_count >= opt.completes_needed
- || ur->n.u.marginal_count >= opt.marginals_needed )
- ur->n.u.validity = TRUST_FULLY;
- else if( ur->n.u.fully_count || ur->n.u.marginal_count )
- ur->n.u.validity = TRUST_MARGINAL;
-
- if( ur->n.u.validity >= max_validity )
- max_validity = ur->n.u.validity;
- }
- }
-
- node->n.k.validity = max_validity;
- return 0;
-}
-
-
-
-/****************
- * Given the directory record of a key, check whether we can
- * find a path to an ultimately trusted key. We do this by
- * checking all key signatures up to a some depth.
- */
-static int
-verify_key( int max_depth, TRUSTREC *drec, const char *namehash,
- int (*add_fnc)(ulong), unsigned *retflgs )
+int
+get_ownertrust_info (PKT_public_key *pk)
{
- TN tree;
- int keytrust;
- int pv_result;
-
- tree = build_cert_tree( drec->r.dir.lid, 0, opt.max_cert_depth, NULL );
- if( !tree )
- return TRUST_UNDEFINED;
- pv_result = propagate_validity( tree, tree, add_fnc, retflgs );
- if( namehash && tree->n.k.validity != TRUST_ULTIMATE ) {
- /* find the matching user id.
- * We don't do this here if the key is ultimately trusted; in
- * this case there will be no lids for the user IDs and frankly
- * it does not make sense to compare by the name if we do
- * have the secret key.
- * fixme: the way we handle this is too inefficient */
- TN ur;
- TRUSTREC rec;
-
- keytrust = 0;
- for( ur=tree->list; ur; ur = ur->next ) {
- read_record( ur->lid, &rec, RECTYPE_UID );
- if( !memcmp( namehash, rec.r.uid.namehash, 20 ) ) {
- keytrust = ur->n.u.validity;
- break;
- }
- }
- }
- else
- keytrust = tree->n.k.validity;
-
- /* update the cached validity values */
- if( !pv_result
- && keytrust >= TRUST_UNDEFINED
- && tdbio_db_matches_options()
- && ( !drec->r.dir.valcheck || drec->r.dir.validity != keytrust ) ) {
- TN ur;
- TRUSTREC rec;
-
- for( ur=tree->list; ur; ur = ur->next ) {
- read_record( ur->lid, &rec, RECTYPE_UID );
- if( rec.r.uid.validity != ur->n.u.validity ) {
- rec.r.uid.validity = ur->n.u.validity;
- write_record( &rec );
- }
- }
-
- drec->r.dir.validity = tree->n.k.validity;
- drec->r.dir.valcheck = make_timestamp();
- write_record( drec );
- do_sync();
- }
+ unsigned int otrust;
+ int c;
- release_tn_tree( tree );
- return keytrust;
+ otrust = get_ownertrust (pk);
+ c = trust_letter( (otrust & TRUST_MASK) );
+ if( !c )
+ c = '?';
+ return c;
}
-
-/****************
- * we have the pubkey record and all needed informations are in the trustdb
- * but nothing more is known.
+/*
+ * Set the trust value of the given public key to the new value.
+ * The key should be a primary one.
*/
-static int
-do_check( TRUSTREC *dr, unsigned *validity,
- const char *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
+void
+update_ownertrust (PKT_public_key *pk, unsigned int new_trust )
{
- if( !dr->r.dir.keylist ) {
- log_error(_("Ooops, no keys\n"));
- return G10ERR_TRUSTDB;
- }
- if( !dr->r.dir.uidlist ) {
- log_error(_("Ooops, no user IDs\n"));
- return G10ERR_TRUSTDB;
+ TRUSTREC rec;
+ int rc;
+
+ rc = read_trust_record (pk, &rec);
+ if (!rc)
+ {
+ if (DBG_TRUST)
+ log_debug ("update ownertrust from %u to %u\n",
+ (unsigned int)rec.r.trust.ownertrust, new_trust );
+ if (rec.r.trust.ownertrust != new_trust)
+ {
+ rec.r.trust.ownertrust = new_trust;
+ write_record( &rec );
+ revalidation_mark ();
+ do_sync();
+ }
}
+ else if (rc == -1)
+ { /* no record yet - create a new one */
+ size_t dummy;
- if( retflgs )
- *retflgs &= ~(16|32); /* reset the 2 special flags */
+ if (DBG_TRUST)
+ log_debug ("insert ownertrust %u\n", new_trust );
- if( (dr->r.dir.ownertrust & TRUST_FLAG_DISABLED) )
- *validity = 0; /* no need to check further */
- else if( namehash ) {
- /* Fixme: use a cache */
- *validity = verify_key( opt.max_cert_depth, dr, namehash,
- add_fnc, retflgs );
+ memset (&rec, 0, sizeof rec);
+ rec.recnum = tdbio_new_recnum ();
+ rec.rectype = RECTYPE_TRUST;
+ fingerprint_from_pk (pk, rec.r.trust.fingerprint, &dummy);
+ rec.r.trust.ownertrust = new_trust;
+ write_record (&rec);
+ revalidation_mark ();
+ do_sync();
+ rc = 0;
}
- else if( !add_fnc
- && tdbio_db_matches_options()
- /* FIXME, TODO: This comparision is WRONG ! */
- && dr->r.dir.valcheck
- > tdbio_read_modify_stamp( (dr->r.dir.validity < TRUST_FULLY) )
- && dr->r.dir.validity )
- *validity = dr->r.dir.validity;
- else
- *validity = verify_key( opt.max_cert_depth, dr, NULL,
- add_fnc, retflgs );
-
- if( !(*validity & TRUST_MASK) )
- *validity = TRUST_UNDEFINED;
-
- if( (dr->r.dir.ownertrust & TRUST_FLAG_DISABLED) )
- *validity |= TRUST_FLAG_DISABLED;
-
- if( dr->r.dir.dirflags & DIRF_REVOKED )
- *validity |= TRUST_FLAG_REVOKED;
-
- /* If we have changed some ownertrusts, set the trustdb timestamps
- * and do a sync */
- if( retflgs && (*retflgs & (16|32)) ) {
- tdbio_write_modify_stamp( (*retflgs & 16), (*retflgs & 32) );
- do_sync();
+ else
+ {
+ tdbio_invalid ();
}
-
-
- return 0;
}
-
-
-/***********************************************
- ********* Change trustdb values **************
- ***********************************************/
-
-int
-update_ownertrust( ulong lid, unsigned new_trust )
-{
- TRUSTREC rec;
-
- init_trustdb();
- read_record( lid, &rec, RECTYPE_DIR );
- if( DBG_TRUST )
- log_debug("update_ownertrust of %lu from %u to %u\n",
- lid, (unsigned)rec.r.dir.ownertrust, new_trust );
- rec.r.dir.ownertrust = new_trust;
- write_record( &rec );
- do_sync();
- return 0;
-}
-
-
-int
-clear_trust_checked_flag( PKT_public_key *pk )
+/*
+ * Note: Caller has to do a sync
+*/
+static void
+update_validity (PKT_public_key *pk, const byte *namehash,
+ int depth, int validity)
{
- TRUSTREC rec;
- int rc;
-
- if( opt.dry_run )
- return 0;
-
- init_trustdb();
- rc = get_dir_record( pk, &rec );
- if( rc )
- return rc;
-
- /* check whether they are already reset */
- if( !(rec.r.dir.dirflags & DIRF_CHECKED) && !rec.r.dir.valcheck )
- return 0;
-
- /* reset the flag */
- rec.r.dir.dirflags &= ~DIRF_CHECKED;
- rec.r.dir.valcheck = 0;
- write_record( &rec );
- do_sync();
- return 0;
+ TRUSTREC trec, vrec;
+ int rc;
+ ulong recno;
+
+ rc = read_trust_record (pk, &trec);
+ if (rc && rc != -1)
+ {
+ tdbio_invalid ();
+ return;
+ }
+ if (rc == -1) /* no record yet - create a new one */
+ {
+ size_t dummy;
+
+ rc = 0;
+ memset (&trec, 0, sizeof trec);
+ trec.recnum = tdbio_new_recnum ();
+ trec.rectype = RECTYPE_TRUST;
+ fingerprint_from_pk (pk, trec.r.trust.fingerprint, &dummy);
+ trec.r.trust.ownertrust = 0;
+ }
+
+ /* locate an existing one */
+ recno = trec.r.trust.validlist;
+ while (recno)
+ {
+ read_record (recno, &vrec, RECTYPE_VALID);
+ if ( !memcmp (vrec.r.valid.namehash, namehash, 20) )
+ break;
+ recno = vrec.r.valid.next;
+ }
+
+ if (!recno) /* insert a new validity record */
+ {
+ memset (&vrec, 0, sizeof vrec);
+ vrec.recnum = tdbio_new_recnum ();
+ vrec.rectype = RECTYPE_VALID;
+ memcpy (vrec.r.valid.namehash, namehash, 20);
+ vrec.r.valid.next = trec.r.trust.validlist;
+ }
+ vrec.r.valid.validity = validity;
+ write_record (&vrec);
+ trec.r.trust.depth = depth;
+ trec.r.trust.validlist = vrec.recnum;
+ write_record (&trec);
}
-
-
/***********************************************
********* Query trustdb values **************
***********************************************/
-
-/****************
- * This function simply looks for the key in the trustdb
- * and makes sure that pk->local_id is set to the correct value.
- * Return: 0 = found
- * -1 = not found
- * other = error
+/*
+ * Return the validity information for PK. If the namehash is not
+ * NULL, the validity of the corresponsing user ID is returned,
+ * otherwise, a reasonable value for the entire key is returned.
*/
-int
-query_trust_record( PKT_public_key *pk )
+unsigned int
+get_validity (PKT_public_key *pk, const byte *namehash)
{
- TRUSTREC rec;
- init_trustdb();
- return get_dir_record( pk, &rec );
-}
-
-
-/****************
- * Get the trustlevel for this PK.
- * Note: This does not ask any questions
- * Returns: 0 okay of an errorcode
- *
- * It operates this way:
- * locate the pk in the trustdb
- * found:
- * Do we have a valid cache record for it?
- * yes: return trustlevel from cache
- * no: make a cache record and all the other stuff
- * not found:
- * try to insert the pubkey into the trustdb and check again
- *
- * Problems: How do we get the complete keyblock to check that the
- * cache record is actually valid? Think we need a clever
- * cache in getkey.c to keep track of this stuff. Maybe it
- * is not necessary to check this if we use a local pubring. Hmmmm.
- */
-int
-check_trust( PKT_public_key *pk, int *r_trustlevel,
- const byte *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
-{
- TRUSTREC rec;
- unsigned int trustlevel = TRUST_UNKNOWN;
- int rc=0;
- u32 cur_time;
- u32 keyid[2];
-
-
- init_trustdb();
- keyid_from_pk( pk, keyid );
-
- /* get the pubkey record */
- if( pk->local_id ) {
- read_record( pk->local_id, &rec, RECTYPE_DIR );
- }
- else { /* no local_id: scan the trustdb */
- if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 ) {
- log_error(_("check_trust: search dir record failed: %s\n"),
- g10_errstr(rc));
- return rc;
- }
- else if( rc == -1 && opt.dry_run )
- return G10ERR_GENERAL;
- else if( rc == -1 ) { /* not found - insert */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error(_("key %08lX: insert trust record failed: %s\n"),
- (ulong)keyid[1], g10_errstr(rc));
- goto leave;
- }
- log_info(_("key %08lX.%lu: inserted into trustdb\n"),
- (ulong)keyid[1], pk->local_id );
- /* and re-read the dir record */
- read_record( pk->local_id, &rec, RECTYPE_DIR );
- }
- }
- cur_time = make_timestamp();
- if( pk->timestamp > cur_time ) {
- log_info(_("key %08lX.%lu: created in future "
- "(time warp or clock problem)\n"),
- (ulong)keyid[1], pk->local_id );
- if( !opt.ignore_time_conflict )
- return G10ERR_TIME_CONFLICT;
- }
-
- if( !(rec.r.dir.dirflags & DIRF_CHECKED) )
- check_trust_record( &rec, 0 );
- else if( rec.r.dir.checkat && rec.r.dir.checkat <= cur_time )
- check_trust_record( &rec, 0 );
- else if( (rec.r.dir.dirflags & DIRF_NEWKEYS) )
- check_trust_record( &rec, 1 );
-
- if( pk->expiredate && pk->expiredate <= cur_time ) {
- log_info(_("key %08lX.%lu: expired at %s\n"),
- (ulong)keyid[1], pk->local_id,
- asctimestamp( pk->expiredate) );
- trustlevel = TRUST_EXPIRED;
- }
- else {
- rc = do_check( &rec, &trustlevel, namehash, add_fnc, retflgs );
- if( rc ) {
- log_error(_("key %08lX.%lu: trust check failed: %s\n"),
- (ulong)keyid[1], pk->local_id, g10_errstr(rc));
- return rc;
- }
- }
-
- /* is a subkey has been requested, we have to check its keyflags */
- if( !rc ) {
- TRUSTREC krec;
- byte fpr[MAX_FINGERPRINT_LEN] = {0}; /* to avoid compiler warnings */
- size_t fprlen = 0;
- ulong recno;
- int kcount=0;
-
- for( recno = rec.r.dir.keylist; recno; recno = krec.r.key.next ) {
- read_record( recno, &krec, RECTYPE_KEY );
- if( ++kcount == 1 )
- continue; /* skip the primary key */
- if( kcount == 2 ) /* now we need the fingerprint */
- fingerprint_from_pk( pk, fpr, &fprlen );
-
- if( krec.r.key.fingerprint_len == fprlen
- && !memcmp( krec.r.key.fingerprint, fpr, fprlen ) ) {
- /* found the subkey */
- if( (krec.r.key.keyflags & KEYF_REVOKED) )
- trustlevel |= TRUST_FLAG_SUB_REVOKED;
- /* should we check for keybinding here??? */
- /* Hmmm: Maybe this whole checking stuff should not go
- * into the trustdb, but be done direct from the keyblock.
- * Chnage this all when we add an abstarction layer around
- * the way certificates are handled by different standards */
- break;
- }
- }
- }
-
-
- leave:
- if( DBG_TRUST )
- log_debug("check_trust() returns trustlevel %04x.\n", trustlevel);
- *r_trustlevel = trustlevel;
- return 0;
-}
-
-
-/****************
- * scan the whole trustdb and mark all signature records whose keys
- * are freshly imported.
- */
-static void
-mark_fresh_keys()
-{
- TRUSTREC dirrec, rec;
- ulong recnum, lid;
- int i;
-
- memset( &dirrec, 0, sizeof dirrec );
-
- for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- if( rec.rectype != RECTYPE_SIG )
- continue;
- /* if we have already have the dir record, we can check it now */
- if( dirrec.recnum == rec.r.sig.lid
- && (dirrec.r.dir.dirflags & DIRF_NEWKEYS) )
- continue; /* flag is already set */
-
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( !(lid=rec.r.sig.sig[i].lid) )
- continue; /* skip deleted sigs */
- if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) )
- continue; /* skip checked signatures */
- if( qry_lid_table_flag( fresh_imported_keys, lid, NULL ) )
- continue; /* not in the list of new keys */
- read_record( rec.r.sig.lid, &dirrec, RECTYPE_DIR );
- if( !(dirrec.r.dir.dirflags & DIRF_NEWKEYS) ) {
- dirrec.r.dir.dirflags |= DIRF_NEWKEYS;
- write_record( &dirrec );
- }
- break;
- }
+ TRUSTREC trec, vrec;
+ int rc;
+ ulong recno;
+ unsigned int validity;
+
+ init_trustdb ();
+ if (!did_nextcheck)
+ {
+ ulong scheduled;
+
+ did_nextcheck = 1;
+ scheduled = tdbio_read_nextcheck ();
+ if (scheduled && scheduled <= make_timestamp ())
+ {
+ if (opt.no_auto_check_trustdb)
+ log_info ("please do a --check-trustdb\n");
+ else {
+ log_info (_("checking the trustdb\n"));
+ validate_keys (0);
+ }
+ }
}
- do_sync();
-
- clear_lid_table( fresh_imported_keys );
- fresh_imported_keys_count = 0;
+ rc = read_trust_record (pk, &trec);
+ if (rc && rc != -1)
+ {
+ tdbio_invalid ();
+ return 0;
+ }
+ if (rc == -1) /* no record found */
+ return TRUST_UNKNOWN;
+
+ /* loop over all user IDs */
+ recno = trec.r.trust.validlist;
+ validity = 0;
+ while (recno)
+ {
+ read_record (recno, &vrec, RECTYPE_VALID);
+ if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
+ validity = (vrec.r.valid.validity & TRUST_MASK);
+ if ( namehash && !memcmp (vrec.r.valid.namehash, namehash, 20) )
+ break;
+ recno = vrec.r.valid.next;
+ }
+
+ if (recno) /* okay, use the user ID associated one */
+ validity = (vrec.r.valid.validity & TRUST_MASK);
+
+ if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
+ validity |= TRUST_FLAG_DISABLED;
+
+ /* for convenience set some flags from the key */
+ if (pk->is_revoked)
+ validity |= TRUST_FLAG_REVOKED;
+ if (pk->has_expired)
+ validity = (validity & ~TRUST_MASK) | TRUST_EXPIRED;
+
+ return validity;
}
-
int
-query_trust_info( PKT_public_key *pk, const byte *namehash )
+get_validity_info (PKT_public_key *pk, const byte *namehash)
{
int trustlevel;
int c;
- init_trustdb();
- if( check_trust( pk, &trustlevel, namehash, NULL, NULL ) )
- return '?';
+ trustlevel = get_validity (pk, namehash);
if( trustlevel & TRUST_FLAG_DISABLED )
return 'd';
if( trustlevel & TRUST_FLAG_REVOKED )
return 'r';
- c = trust_letter( (trustlevel & TRUST_MASK) );
+ c = trust_letter ( (trustlevel & TRUST_MASK) );
if( !c )
c = '?';
return c;
@@ -2481,76 +747,10 @@ query_trust_info( PKT_public_key *pk, const byte *namehash )
-/****************
- * Return the assigned ownertrust value for the given LID
- */
-unsigned
-get_ownertrust( ulong lid )
-{
- TRUSTREC rec;
-
- init_trustdb();
- read_record( lid, &rec, RECTYPE_DIR );
- return rec.r.dir.ownertrust;
-}
-
-int
-get_ownertrust_info( ulong lid )
-{
- unsigned otrust;
- int c;
-
- init_trustdb();
- otrust = get_ownertrust( lid );
- c = trust_letter( (otrust & TRUST_MASK) );
- if( !c )
- c = '?';
- return c;
-}
-
-
void
list_trust_path( const char *username )
{
- int rc;
- ulong lid;
- TRUSTREC rec;
- TN tree;
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-
- init_trustdb();
- if( (rc = get_pubkey_byname (pk, username, NULL, NULL )) )
- log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
- else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
- log_error(_("problem finding '%s' in trustdb: %s\n"),
- username, g10_errstr(rc));
- else if( rc == -1 ) {
- log_info(_("user '%s' not in trustdb - inserting\n"), username);
- rc = insert_trust_record_by_pk( pk );
- if( rc )
- log_error(_("failed to put '%s' into trustdb: %s\n"),
- username, g10_errstr(rc));
- else {
- assert( pk->local_id );
- }
- }
- lid = pk->local_id;
-
- tree = build_cert_tree( lid, 0, opt.max_cert_depth, NULL );
- if( tree )
- propagate_validity( tree, tree, NULL, NULL );
- if( opt.with_colons )
- dump_tn_tree_with_colons( 0, tree );
- else
- dump_tn_tree( stdout, 0, tree );
- /*printf("(alloced tns=%d max=%d)\n", alloced_tns, max_alloced_tns );*/
- release_tn_tree( tree );
- /*printf("Ownertrust=%c Validity=%c\n", get_ownertrust_info( lid ),
- query_trust_info( pk, NULL ) ); */
-
- free_public_key( pk );
-
}
@@ -2579,67 +779,6 @@ enum_cert_paths( void **context, ulong *lid,
unsigned *ownertrust, unsigned *validity )
{
return -1;
- #if 0
- struct enum_cert_paths_ctx *ctx;
- fixme: ..... tsl;
-
- init_trustdb();
- if( !lid ) { /* release the context */
- if( *context ) {
- FIXME: ........tsl2;
-
- ctx = *context;
- for(tsl = ctx->tsl_head; tsl; tsl = tsl2 ) {
- tsl2 = tsl->next;
- m_free( tsl );
- }
- *context = NULL;
- }
- return -1;
- }
-
- if( !*context ) {
- FIXME .... *tmppath;
- TRUSTREC rec;
-
- if( !*lid )
- return -1;
-
- ctx = m_alloc_clear( sizeof *ctx );
- *context = ctx;
- /* collect the paths */
- #if 0
- read_record( *lid, &rec, RECTYPE_DIR );
- tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
- tsl = NULL;
- collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &tsl );
- m_free( tmppath );
- sort_tsl_list( &tsl );
- #endif
- /* setup the context */
- ctx->tsl_head = tsl;
- ctx->tsl = ctx->tsl_head;
- ctx->idx = 0;
- }
- else
- ctx = *context;
-
- while( ctx->tsl && ctx->idx >= ctx->tsl->pathlen ) {
- ctx->tsl = ctx->tsl->next;
- ctx->idx = 0;
- }
- tsl = ctx->tsl;
- if( !tsl )
- return -1; /* eof */
-
- if( ownertrust )
- *ownertrust = tsl->path[ctx->idx].otrust;
- if( validity )
- *validity = tsl->path[ctx->idx].trust;
- *lid = tsl->path[ctx->idx].lid;
- ctx->idx++;
- return ctx->idx-1;
- #endif
}
@@ -2651,42 +790,445 @@ enum_cert_paths_print( void **context, FILE *fp,
int refresh, ulong selected_lid )
{
return;
- #if 0
- struct enum_cert_paths_ctx *ctx;
- FIXME......... tsl;
-
- if( !*context )
- return;
- init_trustdb();
- ctx = *context;
- if( !ctx->tsl )
- return;
- tsl = ctx->tsl;
-
- if( !fp )
- fp = stderr;
-
- if( refresh ) { /* update the ownertrust and if possible the validity */
- int i;
- int match = tdbio_db_matches_options();
-
- for( i = 0; i < tsl->pathlen; i++ ) {
- TRUSTREC rec;
-
- read_record( tsl->path[i].lid, &rec, RECTYPE_DIR );
- tsl->path[i].otrust = rec.r.dir.ownertrust;
- /* update validity only if we have it in the cache
- * calculation is too time consuming */
- if( match && rec.r.dir.valcheck && rec.r.dir.validity ) {
- tsl->path[i].trust = rec.r.dir.validity;
- if( rec.r.dir.dirflags & DIRF_REVOKED )
- tsl->path[i].trust = TRUST_FLAG_REVOKED;
- }
- }
+}
+
+
+
+/****************************************
+ *********** NEW NEW NEW ****************
+ ****************************************/
+
+static unsigned int
+ask_ownertrust (u32 *kid)
+{
+ PKT_public_key *pk;
+ int rc;
+ unsigned int ot;
+
+ pk = m_alloc_clear (sizeof *pk);
+ rc = get_pubkey (pk, kid);
+ if (rc)
+ {
+ log_error (_("public key %08lX not found: %s\n"),
+ (ulong)kid[1], g10_errstr(rc) );
+ return TRUST_UNKNOWN;
+ }
+
+ if (edit_ownertrust (pk, 0))
+ ot = get_ownertrust (pk);
+ else
+ ot = TRUST_UNDEFINED;
+ free_public_key( pk );
+ return ot;
+}
+
+
+static int
+search_skipfnc (void *opaque, u32 *kid)
+{
+ return test_key_hash_table ((KeyHashTable)opaque, kid);
+}
+
+/*
+ * Scan all keys and return a key_array of all keys which are
+ * indicated as found by the supplied CMPFNC. The caller has to pass
+ * a keydb handle so that we don't use to create our own. Returns
+ * either a key_array or NULL in case of an error. No results found
+ * are indicated by an empty array. Caller hast to release the
+ * returned array.
+ */
+static struct key_array *
+make_key_array (KEYDB_HANDLE hd, KeyHashTable visited,
+ int (*cmpfnc)(KBNODE kb, void *opaque), void *cmpval)
+{
+ KBNODE keyblock = NULL;
+ struct key_array *keys = NULL;
+ size_t nkeys, maxkeys;
+ int rc;
+ KEYDB_SEARCH_DESC desc;
+
+ maxkeys = 1000;
+ keys = m_alloc ((maxkeys+1) * sizeof *keys);
+ nkeys = 0;
+
+ rc = keydb_search_reset (hd);
+ if (rc)
+ {
+ log_error ("keydb_search_reset failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
+ }
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FIRST;
+ desc.skipfnc = search_skipfnc;
+ desc.skipfncvalue = visited;
+ rc = keydb_search (hd, &desc, 1);
+ if (rc == -1)
+ {
+ keys[nkeys].keyblock = NULL;
+ return keys;
+ }
+ if (rc)
+ {
+ log_error ("keydb_search_first failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
+ }
+
+ desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */
+ do
+ {
+ rc = keydb_get_keyblock (hd, &keyblock);
+ if (rc)
+ {
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
+ }
+
+ if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
+ {
+ log_debug ("ooops: invalid pkttype %d encountered\n",
+ keyblock->pkt->pkttype);
+ dump_kbnode (keyblock);
+ release_kbnode(keyblock);
+ continue;
+ }
+
+ clear_kbnode_flags (keyblock);
+ if (cmpfnc (keyblock, cmpval))
+ {
+ u32 kid[2];
+
+ if (nkeys == maxkeys) {
+ maxkeys += 1000;
+ keys = m_realloc (keys, (maxkeys+1) * sizeof *keys);
+ }
+ keys[nkeys++].keyblock = keyblock;
+ /* This key is signed - don't check it again */
+ keyid_from_pk (keyblock->pkt->pkt.public_key, kid);
+ add_key_hash_table (visited, kid);
+ }
+ else
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ }
+ while ( !(rc = keydb_search (hd, &desc, 1)) );
+ if (rc && rc != -1)
+ {
+ log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
+ }
+
+ keys[nkeys].keyblock = NULL;
+ return keys;
+}
+
+
+static void
+dump_key_array (int depth, struct key_array *keys)
+{
+ struct key_array *kar;
+
+ for (kar=keys; kar->keyblock; kar++)
+ {
+ KBNODE node = kar->keyblock;
+ u32 kid[2];
+
+ keyid_from_pk(node->pkt->pkt.public_key, kid);
+ printf ("%d:%08lX%08lX:K::%c::::\n",
+ depth, (ulong)kid[0], (ulong)kid[1], '?');
+
+ for (; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ int len = node->pkt->pkt.user_id->len;
+
+ if (len > 30)
+ len = 30;
+ printf ("%d:%08lX%08lX:U:::%c:::",
+ depth, (ulong)kid[0], (ulong)kid[1],
+ (node->flag & 4)? 'f':
+ (node->flag & 2)? 'm':
+ (node->flag & 1)? 'q':'-');
+ print_string (stdout, node->pkt->pkt.user_id->name, len, ':');
+ putchar (':');
+ putchar ('\n');
+ }
+ }
}
+}
- print_path( tsl->pathlen, tsl->path, fp, selected_lid );
- #endif
+
+static void
+store_validation_status (int depth, KBNODE keyblock)
+{
+ KBNODE node;
+ byte namehash[20];
+ int status;
+ int any = 0;
+
+ for (node=keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+
+ if (node->flag & 4)
+ status = TRUST_FULLY;
+ else if (node->flag & 2)
+ status = TRUST_MARGINAL;
+ else if (node->flag & 1)
+ status = TRUST_UNDEFINED;
+ else
+ status = 0;
+
+ if (status)
+ {
+ if( uid->photo )
+ rmd160_hash_buffer (namehash, uid->photo, uid->photolen);
+ else
+ rmd160_hash_buffer (namehash, uid->name, uid->len );
+
+ update_validity (keyblock->pkt->pkt.public_key,
+ namehash, depth, status);
+ any = 1;
+ }
+ }
+ }
+
+ if (any)
+ do_sync ();
+}
+
+/*
+ * Return true if the key is signed by one of the keys in the given
+ * key ID list. User IDs with a valid signature are marked by node
+ * flags as follows:
+ * flag bit 0: There is at least one signature
+ * 1: There is marginal confidence that this is a legitimate uid
+ * 2: There is full confidence that this is a legitimate uid.
+ */
+static int
+cmp_kid_for_make_key_array (KBNODE kb, void *opaque)
+{
+ struct key_item *klist = opaque;
+ struct key_item *kr;
+ KBNODE node, uidnode=NULL;
+ u32 main_kid[2];
+ int issigned=0, any_signed = 0, fully_count =0, marginal_count = 0;
+
+ keyid_from_pk(kb->pkt->pkt.public_key, main_kid);
+ for (node=kb; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ if (uidnode && issigned)
+ {
+ if (fully_count >= opt.completes_needed
+ || marginal_count >= opt.marginals_needed )
+ uidnode->flag |= 4;
+ else if (fully_count || marginal_count)
+ uidnode->flag |= 2;
+ uidnode->flag |= 1;
+ any_signed = 1;
+ }
+ uidnode = node;
+ issigned = 0;
+ fully_count = marginal_count = 0;
+ }
+ else if (node->pkt->pkttype == PKT_SIGNATURE)
+ {
+ PKT_signature *sig = node->pkt->pkt.signature;
+
+ if ( sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
+ ; /* ignore self-signatures */
+ else if ( IS_UID_SIG(sig) )
+ { /* certification */
+ for (kr=klist; kr; kr = kr->next)
+ {
+ if (kr->kid[0] == sig->keyid[0]
+ && kr->kid[1] == sig->keyid[1])
+ {
+ /* Hmmm: Should we first look whether this
+ * signature has been revoked? Avoids problem in
+ * fixing the counters later and we might also
+ * want to check the signature here. It might
+ * also be worth to find the latest signature
+ * first so that we count only one signature for
+ * each key */
+ if (kr->ownertrust == TRUST_ULTIMATE)
+ fully_count = opt.completes_needed;
+ else if (kr->ownertrust == TRUST_FULLY)
+ fully_count++;
+ else if (kr->ownertrust == TRUST_MARGINAL)
+ marginal_count++;
+ issigned = 1;
+ /* fixme: track timestamp to see handle cert revocs */
+ break;
+ }
+ }
+ }
+ else if ( IS_UID_REV(sig) )
+ { /* certificate revocation */
+ /* fixme: reset issigned and counter if needed */
+ }
+ }
+ }
+
+ if (uidnode && issigned)
+ {
+ if (fully_count >= opt.completes_needed
+ || marginal_count >= opt.marginals_needed )
+ uidnode->flag |= 4;
+ else if (fully_count || marginal_count)
+ uidnode->flag |= 2;
+ uidnode->flag |= 1;
+ any_signed = 1;
+ }
+
+ return any_signed;
}
+/*
+ * Run the key validation procedure.
+ *
+ *-----------------------------------
+ * Assume all signatures are good.
+ * Find all ultimately trusted keys (UTK).
+ * mark them all as seen.
+ * Loop over all key to find keys signed by an UTK.
+ * mark key as seen
+ * if OWNERTRUST of that key is undefined
+ * ask user for ownertrust
+ * For each user ID of that key which is signed by the UTK
+ * Calculate validity by counting trusted signatures.
+ * Set validity of user ID
+ * if user ID validity is full
+ * Loop over all keys to find keys signed by current key
+ * skip those which are already seen.
+ *
+ *TODO:
+ *
+ * - Make sure that only valid signatures are checked.
+ * - Skip revoked keys.
+ *
+ */
+static int
+validate_keys (int interactive)
+{
+ int rc = 0;
+ struct key_item *klist = NULL;
+ struct key_item *k;
+ struct key_array *keys = NULL;
+ struct key_array *kar;
+ KEYDB_HANDLE kdb = NULL;
+ KBNODE node;
+ int depth;
+ int key_count;
+ int ot_unknown;
+ int ot_undefined;
+ int ot_marginal;
+ int ot_full;
+ int ot_ultimate;
+ KeyHashTable visited;
+
+ visited = new_key_hash_table ();
+ if (!utk_list)
+ {
+ log_info ("no ultimately trusted keys found\n");
+ goto leave;
+ }
+
+ klist = utk_list;
+ kdb = keydb_new (0);
+
+ for (depth=0; depth < opt.max_cert_depth; depth++)
+ {
+ /* See whether we should assign ownertrust values to the
+ * keys in utk_list.
+ */
+ ot_unknown = ot_undefined = ot_marginal = ot_full = ot_ultimate = 0;
+ for (k=klist; k; k = k->next)
+ {
+ if (interactive && k->ownertrust == TRUST_UNKNOWN)
+ k->ownertrust = ask_ownertrust (k->kid);
+ if (k->ownertrust == TRUST_UNKNOWN)
+ ot_unknown++;
+ else if (k->ownertrust == TRUST_UNDEFINED)
+ ot_undefined++;
+ else if (k->ownertrust == TRUST_MARGINAL)
+ ot_marginal++;
+ else if (k->ownertrust == TRUST_FULLY)
+ ot_full++;
+ else if (k->ownertrust == TRUST_ULTIMATE)
+ ot_ultimate++;
+ }
+
+ /* Find all keys which are signed by a key in kdlist */
+ keys = make_key_array (kdb, visited, cmp_kid_for_make_key_array, klist);
+ if (!keys)
+ {
+ log_error ("make_key_array failed\n");
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+
+
+ for (key_count=0, kar=keys; kar->keyblock; kar++, key_count++)
+ ;
+
+ /* Store the calculated valididation status somewhere */
+ if (opt.verbose > 1)
+ dump_key_array (depth, keys);
+
+ log_info (_("depth=%d keys=%d (-=%d q=%d m=%d f=%d u=%d)\n"),
+ depth, key_count, ot_unknown, ot_undefined,
+ ot_marginal, ot_full, ot_ultimate );
+
+ for (kar=keys; kar->keyblock; kar++)
+ store_validation_status (depth, kar->keyblock);
+
+ /* Build a new kdlist from all fully valid keys in KEYS */
+ if (klist != utk_list)
+ release_key_items (klist);
+ klist = NULL;
+ for (kar=keys; kar->keyblock; kar++)
+ {
+ for (node=kar->keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID && (node->flag & 4))
+ {
+ k = new_key_item ();
+ keyid_from_pk (kar->keyblock->pkt->pkt.public_key, k->kid);
+ k->ownertrust = get_ownertrust (kar->keyblock
+ ->pkt->pkt.public_key);
+ k->next = klist;
+ klist = k;
+ break;
+ }
+ }
+ }
+ release_key_array (keys);
+ keys = NULL;
+ if (!klist)
+ break; /* no need to dive in deeper */
+ }
+
+
+ leave:
+ keydb_release (kdb);
+ release_key_array (keys);
+ release_key_items (klist);
+ release_key_hash_table (visited);
+ if (!rc) /* mark trustDB as checked */
+ {
+ tdbio_write_nextcheck (0);
+ do_sync ();
+ }
+ return rc;
+}
diff --git a/g10/trustdb.h b/g10/trustdb.h
index 81180a429..672d85241 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -24,7 +24,7 @@
/* Trust values must be sorted in ascending order */
#define TRUST_MASK 15
-#define TRUST_UNKNOWN 0 /* o: not yet calculated */
+#define TRUST_UNKNOWN 0 /* o: not yet calculated/assigned */
#define TRUST_EXPIRED 1 /* e: calculation may be invalid */
#define TRUST_UNDEFINED 2 /* q: not enough information for calculation */
#define TRUST_NEVER 3 /* n: never trust this pubkey */
@@ -38,31 +38,31 @@
/*-- trustdb.c --*/
-void list_trust_path( const char *username );
void register_trusted_key( const char *string );
-void check_trustdb( const char *username );
-void update_trustdb( void );
+void check_trustdb (void);
+void update_trustdb (void);
int setup_trustdb( int level, const char *dbname );
void init_trustdb( void );
void sync_trustdb( void );
-int check_trust( PKT_public_key *pk, int *r_trustlevel,
- const byte* nh, int (*add_fnc)(ulong), unsigned *retflgs );
-int query_trust_info( PKT_public_key *pk, const byte *nh );
+
+int trust_letter( unsigned value );
+
+void revalidation_mark (void);
+
+unsigned int get_validity (PKT_public_key *pk, const byte *namehash);
+int get_validity_info (PKT_public_key *pk, const byte *namehash);
+
+void list_trust_path( const char *username );
+
int enum_cert_paths( void **context, ulong *lid,
unsigned *ownertrust, unsigned *validity );
void enum_cert_paths_print( void **context, FILE *fp,
int refresh, ulong selected_lid );
-unsigned get_ownertrust( ulong lid );
-int get_ownertrust_info( ulong lid );
-int keyid_from_lid( ulong lid, u32 *keyid );
-ulong lid_from_keyblock( KBNODE keyblock );
-int query_trust_record( PKT_public_key *pk );
-int clear_trust_checked_flag( PKT_public_key *pk );
-int update_trust_record( KBNODE keyblock, int fast, int *modified );
-int insert_trust_record( KBNODE keyblock );
-int insert_trust_record_by_pk( PKT_public_key *pk );
-int update_ownertrust( ulong lid, unsigned new_trust );
-int trust_letter( unsigned value );
+
+unsigned int get_ownertrust (PKT_public_key *pk);
+int get_ownertrust_info (PKT_public_key *pk);
+void update_ownertrust (PKT_public_key *pk, unsigned int new_trust );
+
/*-- tdbdump.c --*/
void list_trustdb(const char *username);
@@ -70,6 +70,6 @@ void export_ownertrust(void);
void import_ownertrust(const char *fname);
/*-- pkclist.c --*/
-int edit_ownertrust( ulong lid, int mode );
+int edit_ownertrust (PKT_public_key *pk, int mode );
#endif /*G10_TRUSTDB_H*/