From a3af543617515c0bb35b54d456d8c6a5f463dc21 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 24 Sep 2001 16:03:14 +0000 Subject: [PATCH] Revamped the trustDB --- TODO | 11 - doc/ChangeLog | 4 + doc/DETAILS | 2 +- doc/gpg.sgml | 40 +- g10/ChangeLog | 27 +- g10/g10.c | 16 +- g10/getkey.c | 38 +- g10/gpgv.c | 11 +- g10/helptext.c | 9 +- g10/import.c | 33 +- g10/keydb.h | 3 +- g10/keyedit.c | 57 +- g10/keygen.c | 15 +- g10/keylist.c | 6 +- g10/keyring.c | 27 +- g10/keyring.o | Bin 57000 -> 57216 bytes g10/mainproc.c | 6 +- g10/options.h | 1 + g10/pkclist.c | 304 ++--- g10/tdbdump.c | 392 +----- g10/tdbio.c | 785 ++++------- g10/tdbio.h | 133 +- g10/trustdb.c | 3480 ++++++++++++++---------------------------------- g10/trustdb.h | 38 +- 24 files changed, 1682 insertions(+), 3756 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 + + * gpg.sgml: Described --{update,check}-trustdb. + 2001-09-03 Werner Koch * 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. 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. @@ -527,10 +527,34 @@ give the name of this keyserver. ---export-ownertrust +--recv-keys &ParmKeyIDs; -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. + + + +--update-trustdb + +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. + + + +--check-trustdb + +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". @@ -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. +--no-auto-check-trustdb + +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. + + --throw-keyid 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 +2001-09-24 Werner Koch + + * 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 + + 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( edit_ownertrust( find_kbnode( keyblock, - PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) ) + 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, 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 24f1f0460b6770f555a2ebbb8aed7475afca73ae..a188ed02459d541957e5a43062a31dc6bf61dea5 100644 GIT binary patch delta 7439 zcmZ{o3s_Xu+Q-*kYjY8~3W}g63SKaji-LfHkTc$r#0$@7nj#{KTIx{{D{;utY#K>x z={Z(blUgF8Y516R)G$yIQ8}GT%NrFX9@O%ZN7J11zH2tGobUO*%`^Oe?`>W8tl2YV zheXNeVto&-Zg0=~ZrWD)nEPuy$V={a-^v%Zlil41RKDc#s@}=L;HoumcF87}?2)0~ zVbP8y&)d!(X>_w^c-w=tF}7pYKiU_Kaz<=?z!|gMsWl(eAiX7_bYE{QlQX;{(#)Qj z%@3STr?tl4p5<*_9;dSc-&*q?%&avZKp8${n*ZW8)|%V)4A1e+-S0b{Hgi4Xudec2 zeMwe$_q3QjYtw?T$y#%jOKMzF=8_7RY{S-|ur#Z|mbKwZ4UEd3(Nvm#-+EUo>R~rG z*t5R2nX7DBHMQpdRf!E)i?_kpU>v1cO%txHFy;gc5s4ieE8$R?_uLEItoM8ibL<(- zwv5eAbA`2dA1jEJSA4om>1exITF{#v)BTy#+-Ns9TJHufyoMPY&#SP#J*(N4<#3wITC%P8+^`dm!YtLvCg?;i@EI&aecM|$(W1tl zgVpo1#=z7|_v6^w>=15{m*1K{zzdrcB_L%f^!_0K8q6)fC)oL+5OeKMu>*#82~4}$ z;asF!tD-Vt!<+?i-p)aB&8J{jTwAj06k`^41^aS!Xf58%3cakwo1osI>d(Usl4OeY z_gl3U>??Nor;^+;slZ}4pM{o_OmW_YOYG+J0R9EVE%|Lyo`D8R3u3)Xi?4p_57jMQ z+60H$%@&Bps3_hQ56alB4-1C2^fB%`mD?ZtD(utJ0q@KD{@6&U5y$(@Z{@cSaYkyd zTSmv8vlj1Rg~C3~-*)lHFK#Wm^;j6@E$InEu`Z8=yY`x~Z_a|)1W&suR(Ce26)E@z z@(R+iEprp?3naUi8CTezb#Q_`V}m^G7dqYRPw2O}o)u2Ao2%?uHE`40(mUJ6ceSVM zw)CJj6NQ_h!fy7oWrnqQK~`;g7&HYd>0kvADpR3|mcA+!fuWYJ>t&jMwKhxY0Ry!c zWMaTdtwR1iz^r{CwGJuTSvjo3#}FMK7%bZbcGBu)SYV8H3+yMf@8pKS!NB!_QK9}i z+!;T%-X8g#!BqE1{!g+)&_|r)faa<<5g1B$d=(kD7Nz1Jz8)Ry%W|==waOEoEB8mQ>@@&fY0SZU8D|6!7i<|~k@ICW@gma3| ztK!RwFQ_HD0bIf^GW-P4X5mOLD!(sq3A@DZf>re3pPG4LrCVE9A9==#W=bezwZruJWg={Eub);L4CgDu24l z|5EV`mHCy_5`(oLWJux=->a$xi}JV6lQR>4?AR#}yIG;idMGZ@gv=QbEEgsD`#cVw z2)08NjFhEGR&9a|NDlUyru?62Ww1g^D&vy_wb3h7@u!-=>A)2MFAWN9;P1_T)f$06 zQDx!00;YK!*ui>oobd&Ny@6XQUmxc+Y4!#IBj@PtfELC<(S=Zx9RguZvp<=4R95_$$c+S*pn^OE^7l0>%&Eu23 z;Oz$NU~|>*UNabnx7lDkyLVLfN}Z#nd;+dCNX4O68;nD3Fc>?#sCd2__GQJ-ssY`U z$A?AtdI+8fwiOdu&>ZY|i|V+$!PxO2*)46jB^guTGOE*b%;n z_zPY{e2kY6*YY*Qb$mVX39g=#z&5c{{5_Z70>){+gOVEf9^#MrC&XX#L&V?kdg5RB z8RE;lnfMC-o%mneN!-G{a3$d~v8%j`W@$C9@tzd8&hZfeFB7}jhHvvB4#DDO)#DDTdt!!Zrc~PsuoO}f_6RU~2SVt_xMq)RyiP&AdOY9*&BK8zj z#9rbwaeMI{u$sS#d5bF)@Djff`-;wME3@mR5jxVx}f$QUQyBF+@=6HgFZ zi6@G~#Q!52iJulf6HgI0h@TO?_0}7CnusEvE`}IvF|llsPJtO>CUK4^CY~uuh;zlu z#ChTk;yL1N;(W24c&?}%g5P2A0pPs`?*pzfcn|Pt#pS#L_?%)(IWGgFSs6R|HsJe; zE4TyLBOgb)i*E+*pm;am1dNMX;+-LV!TZ3MG@>m;1%LAVvBG+_+idVVgmWCZFrTKLH^YO7EoO#wnj)| zn|O!#Rq>&V@%&#a>L^eu{z3ejI8VGm+#%j5eChD{t9Xp~Z(c2=O51OUGY~+a)`~u?~5(OTSPVSR#8WMsLio@SX={tIV}4s81SkNu2Dn#8lIBJ z48N__-<5qX+~`!Q65+rNM$%`pbYvIHRl}-jEn#1XG^(f;PZ8IMEaIbLDe*C}nz&Z1 zC9V@2i0j2$#3#jG;!_s!DH#oI4%2^#Ch~tJ@JljYCibQThQ^wGp7eJrtAw@fBugg%RSq`naN4x9}oY?;8XgKRE-E-q7x z;tN~?Cp~^O3|9Ptz>lXsieD7XZ9bB4ID?h{C4t|2Ou%Vy&>LOJ?qfT8j92l)vU^5+ zyKEPWt1{rJT#p5hA|A`zu)Phx`H0(}i>ew&C@48MiIHAe9>it`nxD_)^^j^d4qVR7NA zPz;^GbyV>(#Rrx!)|W*qKCU>18E+{zi!sh_Rrb$}p5iegb3$xFa+0)^hsqV@!CjJL zW22rlKW%y=C0UOq?Y5ly~xY$~<{ea_m6aTt3V)Fz&g9v+|Pr zCL~40#YRTOL=B7^vSj|;MY9*=x}0&5Dg9J*U}VbdzA;gdG%&7B*3z733!y$XCMqE^ zDq#>t3SE_hB2xDGaz?r^`&G~;`4)7m^S2Mia z{9LaX&=?t6dqz5rdT#lWbJkh%x^Vql#umxQx^VazE~BoGTN*qrdCKv1fpTq~Klt7O z-z4xYm&fbE`PmEddR=d~hD^pT$&eEfT8&IS(c5j$MfkXubHT2Yubt?l*DYnai~!vhegr+NjE24HG>rp)e&4PPNIPJdUy5 zs0obC_W~Wv*axVIjQxU|#8_vT8i#M~qd~E5lA+TL&Bb^}#&*H9c|XPufnwg*Xb)j5 z7oPagzYsM6&bM-e-teQMM)0X2oO+o-9Gi2zpvUZ8v!V}YoB7z;;#8XO)*Jk^Mg zMC}QWr>OAWT8;VyV}C=1$I2b3(9a&!R5)Kh1Hch}jt*$}0_t$aeno}EJE$-a22Vhk z=LU*-{ZS!42o>U~MtrytpN9(1w8f|c}T!6l4CeiPczaJx>Rqv2g)=;Nqk z;9fw5Ix{NNO$5cd$!J5}5>%Mr3X2i28i94FFteRT!hR$EcOzbh3N!g9D&$>9g#r9& zs6X6rIDl|e7(hQ%7(gN@4j=_>7{C<6&dEUsyshS-!rSIWBe2r&+YSF_!@t$=R~Y_- zhQHeIA23yi&(O1mJ}`6!oHQDIj6G}UGI`{}ng0N( Cpw52) delta 7192 zcmZ{o3tUvyzQ@;I|IJen5Riw2pd)I5AU+UD1Dz?YP<(K%j|@vpeCAP5Z#T}Mqo;7h ztX1dMNsA22jvQa(@lkoj#DfZ$b~C+ZWoap59ZU0(<=p>&&E_BVxp#j)dw$>lZ~fPE z@4aTvRP2L|dtptoad=y|+kVD0mFT}(ejKDW`@bpEgH%`lKAxokE6uPPfk%U*+9zvO za!682&B6&)i$s+<*R2|}oqw@1zuN2A>MGwMO4HP9p!mtNvz{<5Yp$QC*;?)cPbYg6mdr zSqFFF#md4OucNlL$aTw)8Ve{Z)QzqEePhYawZ7Uo{=T2$iiEiy!|7D*qybe$b*VBV z-TAnv`&~CXhCP#kMYygRfMumAID(%`zQt*jB%)Cgk2S2dwd~~I*p=5^?;^i!9p~a+ibQiuq)}8NI_WCgBabJoOiBp}a|yJ?eJUxeM#v`GJ*rv6W*I+<9hYUR1kr2D=Nl;vHUDkklGd zc^&f_@{+IzT+13!8t(2|SgT8I_=M03=mZ-jw05OfRfHcf<|unaKVz9%60ywKp>9Vw zj3X+q(-7mVa(3E|rO!vksF9JKjeTlrWQK7Y<6%aV`ZzKRIV37IKGwu}ooKroN|G?t z^C|g6jg8tOuY!W;be)^5#zzmtKHSkm@bhqVSL0sQg3b|@)cG~zKh?g@S@;-0TrCPjAV#1<(>$ROj|-8Djz2m{syVGF^d59i{7IeYv)HIq`ROrnFKXW<3Jf7?kgIX-)Yo=Zp8h~+oo;8Du60x$Pmk$% zM(3~6j`wkOJ$+e^;Au12dMs*hC&KkPz9()gsrR zC9zDwsns`FQ?vMf*BD?0yConNDQs?OZ3@&?5i zd)352IUNt_7M$9@P^{Ju`YQSdo%$zT?HA1z2BHy~Gw zZjxra$Knv=2G8-FdyI^eXypoP6Eg zM$7sjA>!4PA~^N&0S~!!FLrI!(l1%Vy?p0*2SFWkFdRhI z^S6r*(8vWLaFjV1jxmS9Y36XC$Bz!X=mh7OBcX*k3Vvdah5&spQhp3{W{!120ta0n zojCz=nG<0ub22Pu?hR|0)1aO?1CB9g!Vk>-;RbUS+^shjoWEUU1HJqCW|IS>n1@0E zb1sxI4~NCf4sbC)04tbBz$)f0@I3Rw@G5gYyzS&*G@M~BfUlUx!1v5!;Rf?Kh&S5? zJst)#7eX%cAK-rG2{4v<5=^$(X%~}W1{XX63z?_DQslevA+HcMvI+OZ6wMptdE~yD z-;#%r^EAILk0BRWT!&nYoGUi!J!-D@-;wX5|Fp%sy|!oZWjgF)9>n+%`Hzsuya0SJW|UJ3W7%KSju*pJ_Ll%oTpxDv z6gU+JPs2Lqa(Ii`2}hVK;5hSAIK%u5TxWh3I`VU035m=r;XdY7@UV|*|F42#E?C`e zcUuF`vHv{$g;~K`<`-c-^Gk4m`7dyUc`JO#ybZoZUW}{090zRgl;az=UA$%p+#Hlu zFtSsdza9K|)9^rd*(5^ge|hnv6d zpI?KQ3%&uojn_5AyoU>d&Ed>p zW-)WPIh(n&IiESke2O{NtYl6wUuM3`+{xV4JjLuxGQZ$p8JuTc4&dK5>J<>id;t=e zTOfz|596K&x-TKK|J)~w zrw{HmFgrD~Z|~HM)P9*cWxg;|1=J=P{Zy~oKC)k?XF~0u5cT7ZIM43gm!;9)v*EoZ zfhw>5E}1zzZrJ5t+~kXcp{EYlg3h2c5I7b_w+bEF3{Ntr)1#HG6Gd* z3h`&sf%t<@H zEu@&YlN9snP$};q#hCZ4ResGXzhjjHzQs`a-K6-wIfN9ykDd6x%iN6`k4*LZx%CX@Z zim~Ctq$7nmWoawvgF@UP#d?07QL$d66M-tml7SWbk>U)8TK;g$A5Drgn{AaZvdaI% zDql&86H%m?x0w_Nu-DRKq&R?cq&R>}q&NWQO#~XiFJ#~V;_=R;I2n~5tDdCz*yLFL zFw1|)@*lDMX_i07@}IVRm*rPl{>!9y;Y#^bo&4;T>)>47{ Zkbz$`A(qCfcRoKEUJSlk^qx$u{4Z)uc#{AC 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; + char *p; + size_t n; + u32 keyid[2]; + 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; - } + keyid_from_pk (pk, keyid); + for(;;) { + /* a string with valid answers */ + const char *ans = _("sSmMqQ"); - 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; + 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; + 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; - } + 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 */ @@ -77,256 +62,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. */ @@ -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 - */ +static int +cmp_trec_fpr ( void *fpr, const TRUSTREC *rec ) +{ + return rec->rectype == RECTYPE_TRUST + && !memcmp( rec->r.trust.fingerprint, fpr, 20); +} + + int -tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec ) +tdbio_search_trust_byfpr( const byte *fingerprint, TRUSTREC *rec ) +{ + int rc; + + /* locate the trust record using the hash table */ + rc = lookup_hashtable( get_trusthashrec(), fingerprint, 20, + cmp_trec_fpr, (void*)fingerprint, rec ); + return rc; +} + +int +tdbio_search_trust_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; + for (; fingerlen < 20; fingerlen++ ) + fingerprint[fingerlen] = 0; + return tdbio_search_trust_byfpr (fingerprint, rec); } -static int -cmp_krec_fpr( void *dataptr, 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 ); -} - -int -tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen, - int pubkey_algo, 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) ); - } - return rc; -} - - - -static int -cmp_sdir( void *dataptr, const TRUSTREC *rec ) -{ - const struct cmp_xdir_struct *d = dataptr; - - 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]; -} - - -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 #include #include -#include -#include #include -#include -#include -#include -#include #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; +typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */ - -struct enum_cert_paths_ctx { - int init; - int idx; +/* + * 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; }; -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; -}; - - -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; +/* 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 */ + +/* Keep track on whether we did an update trustDB already */ +static int did_nextcheck; + + +static int validate_keys (int interactive); + /********************************************** - *********** record read write ************** + ************* some helpers ******************* **********************************************/ +static struct key_item * +new_key_item (void) +{ + struct key_item *k; + + k = m_alloc_clear (sizeof *k); + return k; +} + +static void +release_key_items (struct key_item *k) +{ + struct key_item *k2; + + for (; k; k = k2) + { + k2 = k->next; + m_free (k); + } +} + +/* + * 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 KeyHashTable +new_key_hash_table (void) +{ + struct key_item **tbl; + + tbl = m_alloc_clear (256 * sizeof *tbl); + return tbl; +} + +static void +release_key_hash_table (KeyHashTable tbl) +{ + int i; + + if (!tbl) + return; + for (i=0; i < 256; i++) + release_key_items (tbl[i]); + m_free (tbl); +} + +/* + * Returns: True if the keyID is in the given hash table + */ +static int +test_key_hash_table (KeyHashTable tbl, u32 *kid) +{ + struct key_item *k; + + 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 +add_key_hash_table (KeyHashTable tbl, u32 *kid) +{ + 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_key_array ( struct key_array *keys ) +{ + struct key_array *k; + + if (keys) { + for (k=keys; k->keyblock; k++) + release_kbnode (k->keyblock); + m_free (keys); + } +} + + +/********************************************* + ********** Initialization ***************** + *********************************************/ + + + +/* + * 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. + */ +void +register_trusted_key( const char *string ) +{ + 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; + } + + 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 +add_utk (u32 *kid) +{ + struct key_item *k; + + for (k = utk_list; k; k = k->next) + { + if (k->kid[0] == kid[0] && k->kid[1] == kid[1]) + { + return 0; + } + } + + 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; +} + /**************** + * Verify that all our secret keys are usable and put them into the utk_list. + */ +static void +verify_own_keys(void) +{ + TRUSTREC rec; + ulong recnum; + int rc; + struct key_item *k; + int hint_shown = 0; + + if (utk_list) + 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]); + } + } + + /* 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]); + } + } + + + /* release the helper table table */ + release_key_items (user_utk_list); + user_utk_list = NULL; + return; +} + + +/********************************************* + *********** TrustDB stuff ******************* + *********************************************/ + +/* * Read a record but die if it does not exist */ static void -read_record( ulong recno, TRUSTREC *rec, int rectype ) +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(); + 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(); + } } - -/**************** - * Wirte a record but die on error +/* + * Write a record and die on error */ static void -write_record( TRUSTREC *rec ) +write_record (TRUSTREC *rec) { - int rc = tdbio_write_record( rec ); - if( !rc ) - return; - log_error(_("trust record %lu, type %d: write failed: %s\n"), + 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(); + 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(); -} - -/**************** - * sync the db +/* + * sync the TrustDb and die on error */ 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); -} - - - -/********************************************** - ***************** helpers ****************** - **********************************************/ - - -static LOCAL_ID_TABLE -new_lid_table(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; -} - -#if 0 -static void -release_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->next = unused_lid_tables; - unused_lid_tables = tbl; -} -#endif - - -/**************** - * 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; - } -} - - -/**************** - * Add a new item to the table or return 1 if we already have this item - */ -static int -ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag ) -{ - 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; -} - -static int -qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag ) -{ - 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; -} - - -static TN -new_tn(void) -{ - TN t; - - 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; -} - - -static void -release_tn( TN t ) -{ - if( t ) { - t->next = used_tns; - used_tns = t; - alloced_tns--; - } -} - - -static void -release_tn_tree( TN kr ) -{ - TN kr2; - - for( ; kr; kr = kr2 ) { - release_tn_tree( kr->list ); - kr2 = kr->next; - release_tn( kr ); - } -} - - - - -/********************************************** - ****** access by LID and other helpers ******* - **********************************************/ - -/**************** - * Return the keyid from the primary key identified by LID. - */ -int -keyid_from_lid( ulong lid, u32 *keyid ) -{ - 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; -} - - -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; -} - - -static int -get_dir_record( PKT_public_key *pk, TRUSTREC *rec ) -{ - int rc=0; - - 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)); - } - 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; -} - - - -/*********************************************** - ************* Initialization **************** - ***********************************************/ - -void -register_trusted_key( const char *string ) -{ - 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; -} - - -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; - } - } - else if( rc ) { - log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] ); - return; - } - - 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]); - -} - -/**************** - * Verify that all our public keys are in the trustdb. - */ -static int -verify_own_keys(void) -{ - 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 ); - } - } - - /* 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; - } - - enum_secret_keys( &enum_context, NULL, 0 ); /* free context */ - free_secret_key( sk ); - free_public_key( pk ); - return rc; + 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; + if( trustdb_args.init ) + return; - trustdb_args.init = 1; + 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; - - /* verify that our own keys are in the trustDB - * or move them to the trustdb. */ - rc = verify_own_keys(); - - /* 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 ) +trust_letter (unsigned int 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 ; + 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 + * Recreate the WoT but do not ask for new ownertrusts */ -static void -dump_tn_tree_with_colons( int level, TN tree ) +void +check_trustdb() { - 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 ); - } + init_trustdb(); + validate_keys (0); } - -/*********************************************** - ************* 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 ) -{ - 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; - } - } - - - /* 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 - */ -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 ) -{ - 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; -} - - -/**************** - * 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; + init_trustdb(); + validate_keys (1); +} - if( opt.dry_run ) - return; +void +revalidation_mark (void) +{ + 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); +} - init_trustdb(); - kdbhd = keydb_new (0); - rc = keydb_search_first (kdbhd); - if (!rc) { - ulong count=0, err_count=0, new_count=0; + +/*********************************************** + *********** Ownertrust et al. **************** + ***********************************************/ - 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); +static int +read_trust_record (PKT_public_key *pk, TRUSTREC *rec) +{ + 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( rc && rc != -1 ) - log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc)); - - keydb_release (kdbhd); - release_kbnode( keyblock ); + + if (rec->rectype != RECTYPE_TRUST) + { + log_error ("trustdb: record %lu is not a trust record\n", + rec->recnum); + return G10ERR_TRUSTDB; + } + + return 0; } - /**************** - * Do all required checks in the trustdb. This function walks over all - * records in the trustdb and does scheduled processing. + * Return the assigned ownertrust value for the given public key. + * The key should be the primary key. + */ +unsigned int +get_ownertrust ( PKT_public_key *pk) +{ + 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; +} + +/* + * Same as get_wonertrust byt return a trust letter + */ +int +get_ownertrust_info (PKT_public_key *pk) +{ + unsigned int otrust; + int c; + + otrust = get_ownertrust (pk); + c = trust_letter( (otrust & TRUST_MASK) ); + if( !c ) + c = '?'; + return c; +} + +/* + * Set the trust value of the given public key to the new value. + * The key should be a primary one. */ void -check_trustdb( const char *username ) +update_ownertrust (PKT_public_key *pk, unsigned int new_trust ) { - 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 ); + 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; - 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); + if (DBG_TRUST) + log_debug ("insert ownertrust %u\n", new_trust ); + + 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 + { + tdbio_invalid (); + } } - - -/*********************************************** - ********* Trust calculation ***************** - ***********************************************/ - -/**************** - * 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 ) -{ - 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; -} - - +/* + * Note: Caller has to do a sync +*/ static void -upd_one_ownertrust( ulong lid, unsigned new_trust, unsigned *retflgs ) +update_validity (PKT_public_key *pk, const byte *namehash, + int depth, int validity) { - TRUSTREC rec; + 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; - 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 */ + 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; } - /* 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 ); + 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); } -/**************** - * Update the ownertrust in the complete tree. - */ -static void -propagate_ownertrust( TN kr, ulong lid, unsigned trust ) -{ - 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 ); - } -} - -/**************** - * 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 - */ -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 ) -{ - 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(); - } - - release_tn_tree( tree ); - return keytrust; -} - - -/**************** - * we have the pubkey record and all needed informations are in the trustdb - * but nothing more is known. - */ -static int -do_check( TRUSTREC *dr, unsigned *validity, - const char *namehash, int (*add_fnc)(ulong), unsigned *retflgs ) -{ - 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; - } - - if( retflgs ) - *retflgs &= ~(16|32); /* reset the 2 special flags */ - - 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 ); - } - 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(); - } - - - 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 ) -{ - 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; -} - - - /*********************************************** ********* 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 ); + 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); + } + } + } + + 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; } -/**************** - * 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; - } - } - - do_sync(); - - clear_lid_table( fresh_imported_keys ); - fresh_imported_keys_count = 0; -} - - - -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; - } - } - } - - print_path( tsl->pathlen, tsl->path, fp, selected_lid ); - #endif } + +/**************************************** + *********** 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'); + } + } + } +} + + +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*/