diff options
Diffstat (limited to 'g10/trustdb.c')
-rw-r--r-- | g10/trustdb.c | 2158 |
1 files changed, 0 insertions, 2158 deletions
diff --git a/g10/trustdb.c b/g10/trustdb.c deleted file mode 100644 index b3a2b369e..000000000 --- a/g10/trustdb.c +++ /dev/null @@ -1,2158 +0,0 @@ -/* trustdb.c - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 - * Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#ifndef DISABLE_REGEX -#include <sys/types.h> -#ifdef USE_GNU_REGEX -#include "_regex.h" -#else -#include <regex.h> -#endif -#endif /* !DISABLE_REGEX */ - -#include "gpg.h" -#include "errors.h" -#include "iobuf.h" -#include "keydb.h" -#include "memory.h" -#include "util.h" -#include "options.h" -#include "packet.h" -#include "main.h" -#include "i18n.h" -#include "tdbio.h" -#include "trustdb.h" - - -/* - * A structure to store key identification as well as some stuff needed - * for validation - */ -struct key_item { - struct key_item *next; - unsigned int ownertrust,min_ownertrust; - byte trust_depth; - byte trust_value; - char *trust_regexp; - u32 kid[2]; -}; - - -typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */ - -/* - * 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; -}; - - -/* 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 */ - -static int pending_check_trustdb; - -static int validate_keys (int interactive); - - -/********************************************** - ************* some helpers ******************* - **********************************************/ - -static struct key_item * -new_key_item (void) -{ - struct key_item *k; - - k = xcalloc (1,sizeof *k); - return k; -} - -static void -release_key_items (struct key_item *k) -{ - struct key_item *k2; - - for (; k; k = k2) - { - k2 = k->next; - xfree (k->trust_regexp); - xfree (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 10 bits to index a table of 1024 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 = xcalloc (1,1024 * sizeof *tbl); - return tbl; -} - -static void -release_key_hash_table (KeyHashTable tbl) -{ - int i; - - if (!tbl) - return; - for (i=0; i < 1024; i++) - release_key_items (tbl[i]); - xfree (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] & 0x03ff)]; 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 identified by its key ID. - */ -static void -add_key_hash_table (KeyHashTable tbl, u32 *kid) -{ - struct key_item *k, *kk; - - for (k = tbl[(kid[1] & 0x03ff)]; 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] & 0x03ff)]; - tbl[(kid[1] & 0x03ff)] = 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); - xfree (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; - - 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]); - } - } - - /* Put any --trusted-key keys into 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); - } - 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 ) -{ - 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, gpg_strerror (rc) ); - tdbio_invalid(); - } - if (rectype != rec->rectype) - { - log_error(_("trust record %lu is not of requested type %d\n"), - rec->recnum, rectype); - tdbio_invalid(); - } -} - -/* - * Write a record and die on error - */ -static void -write_record (TRUSTREC *rec) -{ - int rc = tdbio_write_record (rec); - if (rc) - { - log_error(_("trust record %lu, type %d: write failed: %s\n"), - rec->recnum, rec->rectype, gpg_strerror (rc) ); - tdbio_invalid(); - } -} - -/* - * sync the TrustDb and die on error - */ -static void -do_sync(void) -{ - int rc = tdbio_sync (); - if(rc) - { - log_error (_("trustdb: sync failed: %s\n"), gpg_strerror (rc) ); - g10_exit(2); - } -} - -static const char * -trust_model_string(void) -{ - switch(opt.trust_model) - { - case TM_PGP: return "PGP"; - case TM_CLASSIC: return "classic"; - case TM_ALWAYS: return "always"; - default: return "unknown"; - } -} - -/**************** - * Perform some checks over the trustdb - * level 0: only open the db - * 1: used for initial program startup - */ -int -setup_trustdb( int level, const char *dbname ) -{ - /* just store the args */ - if( trustdb_args.init ) - return 0; - trustdb_args.level = level; - trustdb_args.dbname = dbname? xstrdup (dbname): NULL; - return 0; -} - -void -init_trustdb() -{ - int rc=0; - int level = trustdb_args.level; - const char* dbname = trustdb_args.dbname; - - if( trustdb_args.init ) - return; - - trustdb_args.init = 1; - - 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", gpg_strerror (rc) ); - - if(opt.trust_model==TM_AUTO) - { - /* Try and set the trust model off of whatever the trustdb says - it is. */ - opt.trust_model=tdbio_read_model(); - - /* Sanity check this ;) */ - if(opt.trust_model!=TM_PGP && opt.trust_model!=TM_CLASSIC) - { - log_info(_("unable to use unknown trust model (%d) - " - "assuming %s trust model\n"),opt.trust_model,"PGP"); - opt.trust_model=TM_PGP; - } - - if(opt.verbose) - log_info(_("using %s trust model\n"),trust_model_string()); - } - - if((opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC) - && !tdbio_db_matches_options()) - pending_check_trustdb=1; -} - - - - -/*********************************************** - ************* Print helpers **************** - ***********************************************/ - -/**************** - * This function returns a letter for a trustvalue Trust flags - * are ignore. - */ -static int -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 '?'; - } -} - -/* The strings here are similar to those in - pkclist.c:do_edit_ownertrust() */ -const char * -trust_value_to_string (unsigned int value) -{ - switch( (value & TRUST_MASK) ) - { - case TRUST_UNKNOWN: return _("unknown"); - case TRUST_EXPIRED: return _("expired"); - case TRUST_UNDEFINED: return _("undefined"); - case TRUST_NEVER: return _("never"); - case TRUST_MARGINAL: return _("marginal"); - case TRUST_FULLY: return _("full"); - case TRUST_ULTIMATE: return _("ultimate"); - default: return "err"; - } -} - -int -string_to_trust_value (const char *str) -{ - if(ascii_strcasecmp(str,"undefined")==0) - return TRUST_UNDEFINED; - else if(ascii_strcasecmp(str,"never")==0) - return TRUST_NEVER; - else if(ascii_strcasecmp(str,"marginal")==0) - return TRUST_MARGINAL; - else if(ascii_strcasecmp(str,"full")==0) - return TRUST_FULLY; - else if(ascii_strcasecmp(str,"ultimate")==0) - return TRUST_ULTIMATE; - else - return -1; -} - -/**************** - * Recreate the WoT but do not ask for new ownertrusts. Special - * feature: In batch mode and without a forced yes, this is only done - * when a check is due. This can be used to run the check from a crontab - */ -void -check_trustdb () -{ - init_trustdb(); - if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC) - { - if (opt.batch && !opt.answer_yes) - { - ulong scheduled; - - scheduled = tdbio_read_nextcheck (); - if (!scheduled) - { - log_info (_("no need for a trustdb check\n")); - return; - } - - if (scheduled > make_timestamp ()) - { - log_info (_("next trustdb check due at %s\n"), - strtimestamp (scheduled)); - return; - } - } - - validate_keys (0); - } - else - log_info (_("no need for a trustdb check with \"%s\" trust model\n"), - trust_model_string()); -} - - -/* - * Recreate the WoT. - */ -void -update_trustdb() -{ - init_trustdb(); - if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC) - validate_keys (1); - else - log_info (_("no need for a trustdb update with \"%s\" trust model\n"), - trust_model_string()); -} - -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 */ - if (tdbio_write_nextcheck (1)) - do_sync (); - pending_check_trustdb = 1; -} - -int -trustdb_pending_check(void) -{ - return pending_check_trustdb; -} - -void -read_trust_options(byte *trust_model,ulong *created,ulong *nextcheck, - byte *marginals,byte *completes,byte *cert_depth) -{ - TRUSTREC opts; - - init_trustdb(); - - read_record(0,&opts,RECTYPE_VER); - - if(trust_model) - *trust_model=opts.r.ver.trust_model; - if(created) - *created=opts.r.ver.created; - if(nextcheck) - *nextcheck=opts.r.ver.nextcheck; - if(marginals) - *marginals=opts.r.ver.marginals; - if(completes) - *completes=opts.r.ver.completes; - if(cert_depth) - *cert_depth=opts.r.ver.cert_depth; -} - - - -/*********************************************** - *********** Ownertrust et al. **************** - ***********************************************/ - -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", - gpg_strerror (rc)); - return rc; - } - - if (rec->rectype != RECTYPE_TRUST) - { - log_error ("trustdb: record %lu is not a trust record\n", - rec->recnum); - return GPG_ERR_TRUSTDB; - } - - return 0; -} - -/**************** - * 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; -} - -unsigned int -get_min_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.min_ownertrust; -} - -/* - * Same as get_ownertrust but this takes the minimum ownertrust value - * into into account, and will bump up the value as needed. - */ -static int -get_ownertrust_with_min (PKT_public_key *pk) -{ - unsigned int otrust,otrust_min; - - otrust = (get_ownertrust (pk) & TRUST_MASK); - otrust_min = get_min_ownertrust (pk); - if(otrust<otrust_min) - { - /* If the trust that the user has set is less than the trust - that was calculated from a trust signature chain, use the - higher of the two. We do this here and not in - get_ownertrust since the underlying ownertrust should not - really be set - just the appearance of the ownertrust. */ - - otrust=otrust_min; - } - - return otrust; -} - -/* - * Same as get_ownertrust but return a trust letter instead of an - * value. This takes the minimum ownertrust value into account. - */ -int -get_ownertrust_info (PKT_public_key *pk) -{ - return trust_letter(get_ownertrust_with_min(pk)); -} - -/* - * Same as get_ownertrust but return a trust string instead of an - * value. This takes the minimum ownertrust value into account. - */ -const char * -get_ownertrust_string (PKT_public_key *pk) -{ - return trust_value_to_string(get_ownertrust_with_min(pk)); -} - -/* - * Set the trust value of the given public key to the new value. - * The key should be a primary one. - */ -void -update_ownertrust (PKT_public_key *pk, unsigned int new_trust ) -{ - TRUSTREC rec; - int rc; - - rc = read_trust_record (pk, &rec); - if (!rc) - { - if (DBG_TRUST) - log_debug ("update ownertrust from %u to %u\n", - (unsigned int)rec.r.trust.ownertrust, new_trust ); - if (rec.r.trust.ownertrust != new_trust) - { - rec.r.trust.ownertrust = new_trust; - write_record( &rec ); - revalidation_mark (); - do_sync (); - } - } - else if (rc == -1) - { /* no record yet - create a new one */ - size_t dummy; - - if (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 (); - } -} - -static void -update_min_ownertrust (u32 *kid, unsigned int new_trust ) -{ - PKT_public_key *pk; - TRUSTREC rec; - int rc; - - pk = xcalloc (1,sizeof *pk); - rc = get_pubkey (pk, kid); - if (rc) - { - log_error (_("public key %08lX not found: %s\n"), - (ulong)kid[1], gpg_strerror (rc) ); - return; - } - - rc = read_trust_record (pk, &rec); - if (!rc) - { - if (DBG_TRUST) - log_debug ("key %08lX: update min_ownertrust from %u to %u\n", - (ulong)kid[1],(unsigned int)rec.r.trust.min_ownertrust, - new_trust ); - if (rec.r.trust.min_ownertrust != new_trust) - { - rec.r.trust.min_ownertrust = new_trust; - write_record( &rec ); - revalidation_mark (); - do_sync (); - } - } - else if (rc == -1) - { /* no record yet - create a new one */ - size_t dummy; - - if (DBG_TRUST) - log_debug ("insert min_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.min_ownertrust = new_trust; - write_record (&rec); - revalidation_mark (); - do_sync (); - rc = 0; - } - else - { - tdbio_invalid (); - } -} - -/* Clear the ownertrust and min_ownertrust values. Return true if a - change actually happened. */ -int -clear_ownertrusts (PKT_public_key *pk) -{ - TRUSTREC rec; - int rc; - - rc = read_trust_record (pk, &rec); - if (!rc) - { - if (DBG_TRUST) - { - log_debug ("clearing ownertrust (old value %u)\n", - (unsigned int)rec.r.trust.ownertrust); - log_debug ("clearing min_ownertrust (old value %u)\n", - (unsigned int)rec.r.trust.min_ownertrust); - } - if (rec.r.trust.ownertrust || rec.r.trust.min_ownertrust) - { - rec.r.trust.ownertrust = 0; - rec.r.trust.min_ownertrust = 0; - write_record( &rec ); - revalidation_mark (); - do_sync (); - return 1; - } - } - else if (rc != -1) - { - tdbio_invalid (); - } - return 0; -} - -/* - * Note: Caller has to do a sync - */ -static void -update_validity (PKT_public_key *pk, PKT_user_id *uid, - int depth, int validity) -{ - TRUSTREC trec, vrec; - int rc; - ulong recno; - - namehash_from_uid(uid); - - rc = read_trust_record (pk, &trec); - if (rc && rc != -1) - { - tdbio_invalid (); - return; - } - if (rc == -1) /* no record yet - create a new one */ - { - size_t dummy; - - rc = 0; - memset (&trec, 0, sizeof trec); - trec.recnum = tdbio_new_recnum (); - trec.rectype = RECTYPE_TRUST; - fingerprint_from_pk (pk, trec.r.trust.fingerprint, &dummy); - trec.r.trust.ownertrust = 0; - } - - /* locate an existing one */ - recno = trec.r.trust.validlist; - while (recno) - { - read_record (recno, &vrec, RECTYPE_VALID); - if ( !memcmp (vrec.r.valid.namehash, uid->namehash, 20) ) - break; - recno = vrec.r.valid.next; - } - - if (!recno) /* insert a new validity record */ - { - memset (&vrec, 0, sizeof vrec); - vrec.recnum = tdbio_new_recnum (); - vrec.rectype = RECTYPE_VALID; - memcpy (vrec.r.valid.namehash, uid->namehash, 20); - vrec.r.valid.next = trec.r.trust.validlist; - trec.r.trust.validlist = vrec.recnum; - } - vrec.r.valid.validity = validity; - vrec.r.valid.full_count = uid->help_full_count; - vrec.r.valid.marginal_count = uid->help_marginal_count; - write_record (&vrec); - trec.r.trust.depth = depth; - write_record (&trec); -} - - -/* reset validity for all user IDs. Caller must sync. */ -static int -clear_validity (PKT_public_key *pk) -{ - TRUSTREC trec, vrec; - int rc; - ulong recno; - int any = 0; - - rc = read_trust_record (pk, &trec); - if (rc && rc != -1) - { - tdbio_invalid (); - return 0; - } - if (rc == -1) /* no record yet - no need to clear it then ;-) */ - return 0; - - /* Clear minimum ownertrust, if any */ - if(trec.r.trust.min_ownertrust) - { - trec.r.trust.min_ownertrust=0; - write_record(&trec); - } - - recno = trec.r.trust.validlist; - while (recno) - { - read_record (recno, &vrec, RECTYPE_VALID); - if ((vrec.r.valid.validity & TRUST_MASK) - || vrec.r.valid.marginal_count || vrec.r.valid.full_count) - { - vrec.r.valid.validity &= ~TRUST_MASK; - vrec.r.valid.marginal_count = vrec.r.valid.full_count = 0; - write_record (&vrec); - any = 1; - } - recno = vrec.r.valid.next; - } - - return any; -} - -/*********************************************** - ********* Query trustdb values ************** - ***********************************************/ - -/* Return true if key is disabled */ -int -cache_disabled_value(PKT_public_key *pk) -{ - int rc; - TRUSTREC trec; - int disabled=0; - - if(pk->is_disabled) - return (pk->is_disabled==2); - - init_trustdb(); - - rc = read_trust_record (pk, &trec); - if (rc && rc != -1) - { - tdbio_invalid (); - goto leave; - } - if (rc == -1) /* no record found, so assume not disabled */ - goto leave; - - if(trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) - disabled=1; - - /* Cache it for later so we don't need to look at the trustdb every - time */ - if(disabled) - pk->is_disabled=2; - else - pk->is_disabled=1; - - leave: - return disabled; -} - -/* - * 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. - */ -unsigned int -get_validity (PKT_public_key *pk, PKT_user_id *uid) -{ - static int did_nextcheck; - TRUSTREC trec, vrec; - int rc; - ulong recno; - unsigned int validity; - u32 kid[2]; - PKT_public_key *main_pk; - - if(uid) - namehash_from_uid(uid); - - init_trustdb (); - if (!did_nextcheck - && (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)) - { - ulong scheduled; - - did_nextcheck = 1; - scheduled = tdbio_read_nextcheck (); - if (scheduled && scheduled <= make_timestamp ()) - { - if (opt.no_auto_check_trustdb) - { - pending_check_trustdb = 1; - log_info (_("please do a --check-trustdb\n")); - } - else - { - log_info (_("checking the trustdb\n")); - validate_keys (0); - } - } - } - - keyid_from_pk (pk, kid); - if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1]) - { /* this is a subkey - get the mainkey */ - main_pk = xcalloc (1,sizeof *main_pk); - rc = get_pubkey (main_pk, pk->main_keyid); - if (rc) - { - log_error ("error getting main key %08lX of subkey %08lX: %s\n", - (ulong)pk->main_keyid[1], (ulong)kid[1], gpg_strerror (rc)); - validity = TRUST_UNKNOWN; - goto leave; - } - } - else - main_pk = pk; - - rc = read_trust_record (main_pk, &trec); - if (rc && rc != -1) - { - tdbio_invalid (); - return 0; - } - if (rc == -1) /* no record found */ - { - validity = TRUST_UNKNOWN; - goto leave; - } - - /* loop over all user IDs */ - recno = trec.r.trust.validlist; - validity = 0; - while (recno) - { - read_record (recno, &vrec, RECTYPE_VALID); - - if(uid) - { - /* If a user ID is given we return the validity for that - user ID ONLY. If the namehash is not found, then there - is no validity at all (i.e. the user ID wasn't - signed). */ - if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0) - { - validity=(vrec.r.valid.validity & TRUST_MASK); - break; - } - } - else - { - /* If no namehash is given, we take the maximum validity - over all user IDs */ - if ( validity < (vrec.r.valid.validity & TRUST_MASK) ) - validity = (vrec.r.valid.validity & TRUST_MASK); - } - - recno = vrec.r.valid.next; - } - - if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) ) - { - validity |= TRUST_FLAG_DISABLED; - pk->is_disabled=2; - } - else - pk->is_disabled=1; - - leave: - /* set some flags direct from the key */ - if (main_pk->is_revoked) - validity |= TRUST_FLAG_REVOKED; - if (main_pk != pk && pk->is_revoked) - validity |= TRUST_FLAG_SUB_REVOKED; - /* Note: expiration is a trust value and not a flag - don't know why - * I initially designed it that way */ - if (main_pk->has_expired || pk->has_expired) - validity = (validity & ~TRUST_MASK) | TRUST_EXPIRED; - - if (pending_check_trustdb) - validity |= TRUST_FLAG_PENDING_CHECK; - - if (main_pk != pk) - free_public_key (main_pk); - return validity; -} - -int -get_validity_info (PKT_public_key *pk, PKT_user_id *uid) -{ - int trustlevel; - - trustlevel = get_validity (pk, uid); - if( trustlevel & TRUST_FLAG_REVOKED ) - return 'r'; - return trust_letter ( trustlevel ); -} - -const char * -get_validity_string (PKT_public_key *pk, PKT_user_id *uid) -{ - int trustlevel; - - trustlevel = get_validity (pk, uid); - if( trustlevel & TRUST_FLAG_REVOKED ) - return _("revoked"); - return trust_value_to_string(trustlevel); -} - -static void -get_validity_counts (PKT_public_key *pk, PKT_user_id *uid) -{ - TRUSTREC trec, vrec; - ulong recno; - - if(pk==NULL || uid==NULL) - BUG(); - - namehash_from_uid(uid); - - uid->help_marginal_count=uid->help_full_count=0; - - init_trustdb (); - - if(read_trust_record (pk, &trec)!=0) - return; - - /* loop over all user IDs */ - recno = trec.r.trust.validlist; - while (recno) - { - read_record (recno, &vrec, RECTYPE_VALID); - - if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0) - { - uid->help_marginal_count=vrec.r.valid.marginal_count; - uid->help_full_count=vrec.r.valid.full_count; - /* printf("Fetched marginal %d, full %d\n",uid->help_marginal_count,uid->help_full_count); */ - break; - } - - recno = vrec.r.valid.next; - } -} - -void -list_trust_path( const char *username ) -{ -} - -/**************** - * Enumerate all keys, which are needed to build all trust paths for - * the given key. This function does not return the key itself or - * the ultimate key (the last point in cerificate chain). Only - * certificate chains which ends up at an ultimately trusted key - * are listed. If ownertrust or validity is not NULL, the corresponding - * value for the returned LID is also returned in these variable(s). - * - * 1) create a void pointer and initialize it to NULL - * 2) pass this void pointer by reference to this function. - * Set lid to the key you want to enumerate and pass it by reference. - * 3) call this function as long as it does not return -1 - * to indicate EOF. LID does contain the next key used to build the web - * 4) Always call this function a last time with LID set to NULL, - * so that it can free its context. - * - * Returns: -1 on EOF or the level of the returned LID - */ -int -enum_cert_paths( void **context, ulong *lid, - unsigned *ownertrust, unsigned *validity ) -{ - return -1; -} - - -/**************** - * Print the current path - */ -void -enum_cert_paths_print( void **context, FILE *fp, - int refresh, ulong selected_lid ) -{ - return; -} - - - -/**************************************** - *********** NEW NEW NEW **************** - ****************************************/ - -static int -ask_ownertrust (u32 *kid,int minimum) -{ - PKT_public_key *pk; - int rc; - int ot; - - pk = xcalloc (1,sizeof *pk); - rc = get_pubkey (pk, kid); - if (rc) - { - log_error (_("public key %08lX not found: %s\n"), - (ulong)kid[1], gpg_strerror (rc) ); - return TRUST_UNKNOWN; - } - - if(opt.force_ownertrust) - { - log_info("force trust for key %08lX%08lX to %s\n", - (ulong)kid[0],(ulong)kid[1], - trust_value_to_string(opt.force_ownertrust)); - update_ownertrust(pk,opt.force_ownertrust); - ot=opt.force_ownertrust; - } - else - { - ot=edit_ownertrust(pk,0); - if(ot>0) - ot = get_ownertrust (pk); - else if(ot==0) - ot = minimum?minimum:TRUST_UNDEFINED; - else - ot = -1; /* quit */ - } - - free_public_key( pk ); - - return ot; -} - - -static void -mark_keyblock_seen (KeyHashTable tbl, KBNODE node) -{ - for ( ;node; node = node->next ) - if (node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) - { - u32 aki[2]; - - keyid_from_pk (node->pkt->pkt.public_key, aki); - add_key_hash_table (tbl, aki); - } -} - - -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, KeyHashTable stored) -{ - KBNODE node; - 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) - { - update_validity (keyblock->pkt->pkt.public_key, - uid, depth, status); - - mark_keyblock_seen(stored,keyblock); - - any = 1; - } - } - } - - if (any) - do_sync (); -} - -/* - * check whether the signature sig is in the klist k - */ -static struct key_item * -is_in_klist (struct key_item *k, PKT_signature *sig) -{ - for (; k; k = k->next) - { - if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1]) - return k; - } - return NULL; -} - -/* - * Mark the signature of the given UID which are used to certify it. - * To do this, we first revmove all signatures which are not valid and - * from the remain ones we look for the latest one. If this is not a - * certification revocation signature we mark the signature by setting - * node flag bit 8. Note that flag bits 9 and 10 are used for internal - * purposes. - */ -static void -mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode, - u32 *main_kid, struct key_item *klist, - u32 curtime, u32 *next_expire) -{ - KBNODE node; - PKT_signature *sig; - - /* first check all signatures */ - for (node=uidnode->next; node; node = node->next) - { - node->flag &= ~(1<<8 | 1<<9 | 1<<10); - if (node->pkt->pkttype == PKT_USER_ID - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) - break; /* ready */ - if (node->pkt->pkttype != PKT_SIGNATURE) - continue; - - sig = node->pkt->pkt.signature; - if (sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1]) - continue; /* ignore self-signatures */ - if (!IS_UID_SIG(sig) && !IS_UID_REV(sig)) - continue; /* we only look at these signature classes */ - if (!is_in_klist (klist, sig)) - continue; /* no need to check it then */ - if (check_key_signature (keyblock, node, NULL)) - continue; /* ignore invalid signatures */ - node->flag |= 1<<9; - } - /* reset the remaining flags */ - for (; node; node = node->next) - node->flag &= ~(1<<8 | 1<<9 | 1 << 10); - - /* kbnode flag usage: bit 9 is here set for signatures to consider, - * bit 10 will be set by the loop to keep track of keyIDs already - * processed, bit 8 will be set for the usable signatures */ - - /* for each cert figure out the latest valid one */ - for (node=uidnode->next; node; node = node->next) - { - KBNODE n, signode; - u32 kid[2]; - u32 sigdate; - - if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) - break; - if ( !(node->flag & (1<<9)) ) - continue; /* not a node to look at */ - if ( (node->flag & (1<<10)) ) - continue; /* signature with a keyID already processed */ - node->flag |= (1<<10); /* mark this node as processed */ - sig = node->pkt->pkt.signature; - signode = node; - sigdate = sig->timestamp; - kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1]; - for (n=uidnode->next; n; n = n->next) - { - if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY) - break; - if ( !(n->flag & (1<<9)) ) - continue; - if ( (n->flag & (1<<10)) ) - continue; /* shortcut already processed signatures */ - sig = n->pkt->pkt.signature; - if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1]) - continue; - n->flag |= (1<<10); /* mark this node as processed */ - - /* If signode is nonrevocable and unexpired and n isn't, - then take signode (skip). It doesn't matter which is - older: if signode was older then we don't want to take n - as signode is nonrevocable. If n was older then we're - automatically fine. */ - - if(((IS_UID_SIG(signode->pkt->pkt.signature) && - !signode->pkt->pkt.signature->flags.revocable && - (signode->pkt->pkt.signature->expiredate==0 || - signode->pkt->pkt.signature->expiredate>curtime))) && - (!(IS_UID_SIG(n->pkt->pkt.signature) && - !n->pkt->pkt.signature->flags.revocable && - (n->pkt->pkt.signature->expiredate==0 || - n->pkt->pkt.signature->expiredate>curtime)))) - continue; - - /* If n is nonrevocable and unexpired and signode isn't, - then take n. Again, it doesn't matter which is older: if - n was older then we don't want to take signode as n is - nonrevocable. If signode was older then we're - automatically fine. */ - - if((!(IS_UID_SIG(signode->pkt->pkt.signature) && - !signode->pkt->pkt.signature->flags.revocable && - (signode->pkt->pkt.signature->expiredate==0 || - signode->pkt->pkt.signature->expiredate>curtime))) && - ((IS_UID_SIG(n->pkt->pkt.signature) && - !n->pkt->pkt.signature->flags.revocable && - (n->pkt->pkt.signature->expiredate==0 || - n->pkt->pkt.signature->expiredate>curtime)))) - { - signode = n; - sigdate = sig->timestamp; - continue; - } - - /* At this point, if it's newer, it goes in as the only - remaining possibilities are signode and n are both either - revocable or expired or both nonrevocable and unexpired. - If the timestamps are equal take the later ordered - packet, presuming that the key packets are hopefully in - their original order. */ - - if (sig->timestamp >= sigdate) - { - signode = n; - sigdate = sig->timestamp; - } - } - sig = signode->pkt->pkt.signature; - if (IS_UID_SIG (sig)) - { /* this seems to be a usable one which is not revoked. - * Just need to check whether there is an expiration time, - * We do the expired certification after finding a suitable - * certification, the assumption is that a signator does not - * want that after the expiration of his certificate the - * system falls back to an older certification which has a - * different expiration time */ - const byte *p; - u32 expire; - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL ); - expire = p? sig->timestamp + buffer_to_u32(p) : 0; - - if (expire==0 || expire > curtime ) - { - signode->flag |= (1<<8); /* yeah, found a good cert */ - if (expire && expire < *next_expire) - *next_expire = expire; - } - } - } -} - -/* Used by validate_one_keyblock to confirm a regexp within a trust - signature. Returns 1 for match, and 0 for no match or regex - error. */ -static int -check_regexp(const char *expr,const char *string) -{ -#ifdef DISABLE_REGEX - /* When DISABLE_REGEX is defined, assume all regexps do not - match. */ - return 0; -#elif defined(__riscos__) - return riscos_check_regexp(expr, string, DBG_TRUST); -#else - int ret; - regex_t pat; - - if(regcomp(&pat,expr,REG_ICASE|REG_NOSUB|REG_EXTENDED)!=0) - return 0; - - ret=regexec(&pat,string,0,NULL,0); - - regfree(&pat); - - if(DBG_TRUST) - log_debug("regexp \"%s\" on \"%s\": %s\n",expr,string,ret==0?"YES":"NO"); - - return (ret==0); -#endif -} - -/* - * 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. - * 8: Used for internal purposes. - * 9: Ditto (in mark_usable_uid_certs()) - * 10: Ditto (ditto) - * This function assumes that all kbnode flags are cleared on entry. - */ -static int -validate_one_keyblock (KBNODE kb, struct key_item *klist, - u32 curtime, u32 *next_expire) -{ - struct key_item *kr; - KBNODE node, uidnode=NULL; - PKT_user_id *uid=NULL; - PKT_public_key *pk = kb->pkt->pkt.public_key; - u32 main_kid[2]; - int issigned=0, any_signed = 0; - - keyid_from_pk(pk, main_kid); - for (node=kb; node; node = node->next) - { - /* A bit of discussion here: is it better for the web of trust - to be built among only self-signed uids? On the one hand, a - self-signed uid is a statement that the key owner definitely - intended that uid to be there, but on the other hand, a - signed (but not self-signed) uid does carry trust, of a sort, - even if it is a statement being made by people other than the - key owner "through" the uids on the key owner's key. I'm - going with the latter. However, if the user ID was - explicitly revoked, or passively allowed to expire, that - should stop validity through the user ID until it is - resigned. -dshaw */ - - if (node->pkt->pkttype == PKT_USER_ID - && !node->pkt->pkt.user_id->is_revoked - && !node->pkt->pkt.user_id->is_expired) - { - if (uidnode && issigned) - { - if (uid->help_full_count >= opt.completes_needed - || uid->help_marginal_count >= opt.marginals_needed ) - uidnode->flag |= 4; - else if (uid->help_full_count || uid->help_marginal_count) - uidnode->flag |= 2; - uidnode->flag |= 1; - any_signed = 1; - } - uidnode = node; - uid=uidnode->pkt->pkt.user_id; - - /* If the selfsig is going to expire... */ - if(uid->expiredate && uid->expiredate<*next_expire) - *next_expire = uid->expiredate; - - issigned = 0; - get_validity_counts(pk,uid); - mark_usable_uid_certs (kb, uidnode, main_kid, klist, - curtime, next_expire); - } - else if (node->pkt->pkttype == PKT_SIGNATURE - && (node->flag & (1<<8)) && uid) - { - /* Note that we are only seeing unrevoked sigs here */ - PKT_signature *sig = node->pkt->pkt.signature; - - kr = is_in_klist (klist, sig); - /* If the trust_regexp does not match, it's as if the sig - did not exist. This is safe for non-trust sigs as well - since we don't accept a regexp on the sig unless it's a - trust sig. */ - if (kr && (kr->trust_regexp==NULL || opt.trust_model!=TM_PGP || - (uidnode && check_regexp(kr->trust_regexp, - uidnode->pkt->pkt.user_id->name)))) - { - if(DBG_TRUST && opt.trust_model==TM_PGP && sig->trust_depth) - log_debug("trust sig on %s, sig depth is %d, kr depth is %d\n", - uidnode->pkt->pkt.user_id->name,sig->trust_depth, - kr->trust_depth); - - /* Are we part of a trust sig chain? We always favor - the latest trust sig, rather than the greater or - lesser trust sig or value. I could make a decent - argument for any of these cases, but this seems to be - what PGP does, and I'd like to be compatible. -dms */ - if(opt.trust_model==TM_PGP && sig->trust_depth - && pk->trust_timestamp<=sig->timestamp - && (sig->trust_depth<=kr->trust_depth - || kr->ownertrust==TRUST_ULTIMATE)) - { - /* If we got here, we know that: - - this is a trust sig. - - it's a newer trust sig than any previous trust - sig on this key (not uid). - - it is legal in that it was either generated by an - ultimate key, or a key that was part of a trust - chain, and the depth does not violate the - original trust sig. - - if there is a regexp attached, it matched - successfully. - */ - - if(DBG_TRUST) - log_debug("replacing trust value %d with %d and " - "depth %d with %d\n", - pk->trust_value,sig->trust_value, - pk->trust_depth,sig->trust_depth); - - pk->trust_value=sig->trust_value; - pk->trust_depth=sig->trust_depth-1; - - /* If the trust sig contains a regexp, record it - on the pk for the next round. */ - if(sig->trust_regexp) - pk->trust_regexp=sig->trust_regexp; - } - - if (kr->ownertrust == TRUST_ULTIMATE) - uid->help_full_count = opt.completes_needed; - else if (kr->ownertrust == TRUST_FULLY) - uid->help_full_count++; - else if (kr->ownertrust == TRUST_MARGINAL) - uid->help_marginal_count++; - issigned = 1; - } - } - } - - if (uidnode && issigned) - { - if (uid->help_full_count >= opt.completes_needed - || uid->help_marginal_count >= opt.marginals_needed ) - uidnode->flag |= 4; - else if (uid->help_full_count || uid->help_marginal_count) - uidnode->flag |= 2; - uidnode->flag |= 1; - any_signed = 1; - } - - return any_signed; -} - - -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 suitable keys from - * kllist. The caller has to pass 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 * -validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust, - struct key_item *klist, u32 curtime, u32 *next_expire) -{ - KBNODE keyblock = NULL; - struct key_array *keys = NULL; - size_t nkeys, maxkeys; - int rc; - KEYDB_SEARCH_DESC desc; - - maxkeys = 1000; - keys = xmalloc ((maxkeys+1) * sizeof *keys); - nkeys = 0; - - rc = keydb_search_reset (hd); - if (rc) - { - log_error ("keydb_search_reset failed: %s\n", gpg_strerror (rc)); - xfree (keys); - return NULL; - } - - memset (&desc, 0, sizeof desc); - desc.mode = KEYDB_SEARCH_MODE_FIRST; - desc.skipfnc = search_skipfnc; - desc.skipfncvalue = full_trust; - 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", gpg_strerror (rc)); - xfree (keys); - return NULL; - } - - desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */ - do - { - PKT_public_key *pk; - - rc = keydb_get_keyblock (hd, &keyblock); - if (rc) - { - log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc)); - xfree (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; - } - - /* prepare the keyblock for further processing */ - merge_keys_and_selfsig (keyblock); - clear_kbnode_flags (keyblock); - pk = keyblock->pkt->pkt.public_key; - if (pk->has_expired || pk->is_revoked) - { - /* it does not make sense to look further at those keys */ - mark_keyblock_seen (full_trust, keyblock); - } - else if (validate_one_keyblock (keyblock, klist, curtime, next_expire)) - { - KBNODE node; - - if (pk->expiredate && pk->expiredate >= curtime - && pk->expiredate < *next_expire) - *next_expire = pk->expiredate; - - if (nkeys == maxkeys) { - maxkeys += 1000; - keys = xrealloc (keys, (maxkeys+1) * sizeof *keys); - } - keys[nkeys++].keyblock = keyblock; - - /* Optimization - if all uids are fully trusted, then we - never need to consider this key as a candidate again. */ - - for (node=keyblock; node; node = node->next) - if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 4)) - break; - - if(node==NULL) - mark_keyblock_seen (full_trust, keyblock); - - keyblock = NULL; - } - - release_kbnode (keyblock); - keyblock = NULL; - } - while ( !(rc = keydb_search (hd, &desc, 1)) ); - if (rc && rc != -1) - { - log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc)); - xfree (keys); - return NULL; - } - - keys[nkeys].keyblock = NULL; - return keys; -} - -/* Caller must sync */ -static void -reset_trust_records (KEYDB_HANDLE hd, KeyHashTable exclude) -{ - int rc; - KBNODE keyblock = NULL; - KEYDB_SEARCH_DESC desc; - int count = 0, nreset = 0; - - rc = keydb_search_reset (hd); - if (rc) - { - log_error ("keydb_search_reset failed: %s\n", gpg_strerror (rc)); - return; - } - - memset (&desc, 0, sizeof desc); - desc.mode = KEYDB_SEARCH_MODE_FIRST; - if(exclude) - { - desc.skipfnc = search_skipfnc; - desc.skipfncvalue = exclude; - } - rc = keydb_search (hd, &desc, 1); - if (rc && rc != -1 ) - log_error ("keydb_search_first failed: %s\n", gpg_strerror (rc)); - else if (!rc) - { - 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", gpg_strerror (rc)); - break; - } - count++; - - if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY) /* paranoid assertion*/ - { - nreset += clear_validity (keyblock->pkt->pkt.public_key); - release_kbnode (keyblock); - } - } - while ( !(rc = keydb_search (hd, &desc, 1)) ); - if (rc && rc != -1) - log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc)); - } - if (opt.verbose) - log_info (_("%d keys processed (%d validity counts cleared)\n"), - count, nreset); -} - -/* - * Run the key validation procedure. - * - * This works this way: - * Step 1: Find all ultimately trusted keys (UTK). - * mark them all as seen and put them into klist. - * Step 2: loop max_cert_times - * Step 3: if OWNERTRUST of any key in klist is undefined - * ask user to assign ownertrust - * Step 4: Loop over all keys in the keyDB which are not marked seen - * Step 5: if key is revoked or expired - * mark key as seen - * continue loop at Step 4 - * Step 6: For each user ID of that key signed by a key in klist - * Calculate validity by counting trusted signatures. - * Set validity of user ID - * Step 7: If any signed user ID was found - * mark key as seen - * End Loop - * Step 8: Build a new klist from all fully trusted keys from step 6 - * End Loop - * Ready - * - */ -static int -validate_keys (int interactive) -{ - int rc = 0; - int quit=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, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate; - KeyHashTable stored,used,full_trust; - u32 start_time, next_expire; - - start_time = make_timestamp (); - next_expire = 0xffffffff; /* set next expire to the year 2106 */ - stored = new_key_hash_table (); - used = new_key_hash_table (); - full_trust = new_key_hash_table (); - /* Fixme: Instead of always building a UTK list, we could just build it - * here when needed */ - if (!utk_list) - { - log_info (_("no ultimately trusted keys found\n")); - goto leave; - } - - kdb = keydb_new (0); - - reset_trust_records (kdb,NULL); - - /* mark all UTKs as used and fully_trusted and set validity to - ultimate */ - for (k=utk_list; k; k = k->next) - { - KBNODE keyblock; - PKT_public_key *pk; - - keyblock = get_pubkeyblock (k->kid); - if (!keyblock) - { - log_error (_("public key of ultimately" - " trusted key %08lX not found\n"), (ulong)k->kid[1]); - continue; - } - mark_keyblock_seen (used, keyblock); - mark_keyblock_seen (stored, keyblock); - mark_keyblock_seen (full_trust, keyblock); - pk = keyblock->pkt->pkt.public_key; - for (node=keyblock; node; node = node->next) - { - if (node->pkt->pkttype == PKT_USER_ID) - update_validity (pk, node->pkt->pkt.user_id, 0, TRUST_ULTIMATE); - } - if ( pk->expiredate && pk->expiredate >= start_time - && pk->expiredate < next_expire) - next_expire = pk->expiredate; - - release_kbnode (keyblock); - do_sync (); - } - - klist = utk_list; - - log_info(_("%d marginal(s) needed, %d complete(s) needed, %s trust model\n"), - opt.marginals_needed,opt.completes_needed,trust_model_string()); - - 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_never = 0; - ot_marginal = ot_full = ot_ultimate = 0; - for (k=klist; k; k = k->next) - { - int min=0; - - /* 120 and 60 are as per RFC2440 */ - if(k->trust_value>=120) - min=TRUST_FULLY; - else if(k->trust_value>=60) - min=TRUST_MARGINAL; - - if(min!=k->min_ownertrust) - update_min_ownertrust(k->kid,min); - - if (interactive && k->ownertrust == TRUST_UNKNOWN) - { - k->ownertrust = ask_ownertrust (k->kid,min); - - if (k->ownertrust == -1) - { - quit=1; - goto leave; - } - } - - /* This can happen during transition from an old trustdb - before trust sigs. It can also happen if a user uses two - different versions of GnuPG or changes the --trust-model - setting. */ - if(k->ownertrust<min) - { - if(DBG_TRUST) - log_debug("key %08lX: " - "overriding ownertrust \"%s\" with \"%s\"\n", - (ulong)k->kid[1], - trust_value_to_string(k->ownertrust), - trust_value_to_string(min)); - - k->ownertrust=min; - } - - if (k->ownertrust == TRUST_UNKNOWN) - ot_unknown++; - else if (k->ownertrust == TRUST_UNDEFINED) - ot_undefined++; - else if (k->ownertrust == TRUST_NEVER) - ot_never++; - 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 = validate_key_list (kdb, full_trust, klist, - start_time, &next_expire); - if (!keys) - { - log_error ("validate_key_list failed\n"); - rc = GPG_ERR_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); - - for (kar=keys; kar->keyblock; kar++) - store_validation_status (depth, kar->keyblock, stored); - - log_info (_("checking at depth %d valid=%d" - " ot(-/q/n/m/f/u)=%d/%d/%d/%d/%d/%d\n"), - depth, key_count, ot_unknown, ot_undefined, - ot_never, ot_marginal, ot_full, ot_ultimate ); - - /* 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)) - { - u32 kid[2]; - - /* have we used this key already? */ - keyid_from_pk (kar->keyblock->pkt->pkt.public_key, kid); - if(test_key_hash_table(used,kid)==0) - { - /* Normally we add both the primary and subkey - ids to the hash via mark_keyblock_seen, but - since we aren't using this hash as a skipfnc, - that doesn't matter here. */ - add_key_hash_table (used,kid); - k = new_key_item (); - k->kid[0]=kid[0]; - k->kid[1]=kid[1]; - k->ownertrust = - (get_ownertrust (kar->keyblock->pkt->pkt.public_key) - & TRUST_MASK); - k->min_ownertrust = - get_min_ownertrust(kar->keyblock->pkt->pkt.public_key); - k->trust_depth= - kar->keyblock->pkt->pkt.public_key->trust_depth; - k->trust_value= - kar->keyblock->pkt->pkt.public_key->trust_value; - if(kar->keyblock->pkt->pkt.public_key->trust_regexp) - k->trust_regexp= - xstrdup (kar->keyblock->pkt-> - pkt.public_key->trust_regexp); - 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 (full_trust); - release_key_hash_table (used); - release_key_hash_table (stored); - if (!rc && !quit) /* mark trustDB as checked */ - { - if (next_expire == 0xffffffff || next_expire < start_time ) - tdbio_write_nextcheck (0); - else - { - tdbio_write_nextcheck (next_expire); - log_info (_("next trustdb check due at %s\n"), - strtimestamp (next_expire)); - } - - if(tdbio_update_version_record()!=0) - { - log_error(_("unable to update trustdb version record: " - "write failed: %s\n"), gpg_strerror (rc)); - tdbio_invalid(); - } - - do_sync (); - pending_check_trustdb = 0; - } - - return rc; -} |