* export.c (parse_export_options): New option sexp-format.
[gnupg.git] / g10 / trustdb.c
index 4f89751..16bd96e 100644 (file)
@@ -1,14 +1,15 @@
 /* trustdb.c
- *     Copyright (c) 1997 by Werner Koch (dd9jn)
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ *                                             Free Software Foundation, Inc.
  *
- * This file is part of G10.
+ * This file is part of GnuPG.
  *
- * G10 is free software; you can redistribute it and/or modify
+ * 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.
  *
- * G10 is distributed in the hope that it will be useful,
+ * 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.
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <errno.h>
 #include <assert.h>
-#include <fcntl.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 "trustdb.h"
 #include "options.h"
 #include "packet.h"
 #include "main.h"
+#include "i18n.h"
+#include "tdbio.h"
+#include "trustdb.h"
 
 
-#define TRUST_RECORD_LEN 40
-#define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5)
-#define MAX_LIST_SIGS_DEPTH  20
-
-struct trust_record {
-    byte rectype;
-    byte reserved;
-    union {
-       struct {            /* version record: */
-           byte magic[2];
-           byte version;   /* should be 1 */
-           byte reserved[3];
-           ulong locked;    /* pid of process which holds a lock */
-           ulong created;   /* timestamp of trustdb creation  */
-           ulong modified;  /* timestamp of last modification */
-           ulong validated; /* timestamp of last validation   */
-           ulong local_id_counter;
-           byte marginals_needed;
-           byte completes_needed;
-           byte max_cert_depth;
-       } version;
-       struct {            /* public key record */
-           ulong local_id;
-           u32   keyid[2];
-           byte pubkey_algo;
-           byte reserved;
-           byte fingerprint[20];
-           byte ownertrust;
-           /* fixme: indicate a flag to */
-       } pubkey;
-       struct {            /* cache record */
-           ulong owner;
-           u32   keyid[2];       /* needed?? */
-           byte valid;
-           byte reserved;
-           byte blockhash[20];
-           byte n_untrusted;
-           byte n_marginal;
-           byte n_fully;
-           byte trustlevel;
-       } cache;
-       struct {
-           ulong owner;  /* local_id of record owner (pubkey record) */
-           ulong chain;  /* offset of next record or NULL for last one */
-           struct {
-               ulong  local_id; /* of pubkey record of signator (0=unused) */
-               byte flag;     /* reserved */
-           } sig[SIGS_PER_RECORD];
-       } sigrec;
-    } r;
-};
-typedef struct trust_record TRUSTREC;
-
-typedef struct {
-    ulong     pubkey_id;   /* localid of the pubkey */
-    ulong     sig_id;     /* returned signature id */
-    unsigned  sig_flag;    /* returned signaure record flag */
-    struct {              /* internal data */
-       int eof;
-       TRUSTREC rec;
-       int index;
-    } ctl;
-} SIGREC_CONTEXT;
-
-typedef struct local_id_info *LOCAL_ID_INFO;
-struct local_id_info {
-    LOCAL_ID_INFO next;
-    ulong lid;
-    unsigned flag;
+/*
+ * 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 trust_info TRUST_INFO;
-struct trust_info {
-    ulong    lid;
-    unsigned trust;
+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;
 };
 
 
-typedef struct trust_seg_list *TRUST_SEG_LIST;
-struct trust_seg_list {
-    TRUST_SEG_LIST next;
-    int   nseg;     /* number of segmens */
-    int   dup;
-    TRUST_INFO seg[1];  /* segment list */
-};
+/* 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 */
 
-typedef struct {
-    TRUST_SEG_LIST tsl;
-    int index;
-} ENUM_TRUST_WEB_CONTEXT;
-
-
-static void create_db( const char *fname );
-static void open_db(void);
-static int  read_record( ulong recnum, TRUSTREC *rec );
-static int  write_record( ulong recnum, TRUSTREC *rec );
-static ulong new_recnum(void);
-static void dump_record( ulong rnum, TRUSTREC *rec, FILE *fp );
-static int walk_sigrecs( SIGREC_CONTEXT *c );
-
-static LOCAL_ID_INFO *new_lid_table(void);
-static void release_lid_table( LOCAL_ID_INFO *tbl );
-static int ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag );
-static int qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag );
-static void upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag );
-
-static void print_user_id( const char *text, u32 *keyid );
-static int do_list_path( TRUST_INFO *stack, int depth, int max_depth,
-                        LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist );
-
-static int list_sigs( ulong pubkey_id );
-static int propagate_trust( TRUST_SEG_LIST tslist );
-static int do_check( ulong pubkeyid, unsigned *trustlevel );
-
-
-static char *db_name;
-static int  db_fd = -1;
-/* a table used to keep track of ultimately trusted keys
- * which are the ones from our secrings */
-static LOCAL_ID_INFO *ultikey_table;
-
-static ulong last_trust_web_key;
-static TRUST_SEG_LIST last_trust_web_tslist;
-
-#define buftoulong( p )  ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
-                      (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
-#define buftoushort( p )  ((*((byte*)(p)) << 8) | (*((byte*)(p)+1)))
-#define ulongtobuf( p, a ) do {                          \
-                           ((byte*)p)[0] = a >> 24;    \
-                           ((byte*)p)[1] = a >> 16;    \
-                           ((byte*)p)[2] = a >>  8;    \
-                           ((byte*)p)[3] = a      ;    \
-                       } while(0)
-#define ushorttobuf( p, a ) do {                          \
-                           ((byte*)p)[0] = a >>  8;    \
-                           ((byte*)p)[1] = a      ;    \
-                       } while(0)
-#define buftou32( p)   buftoulong( (p) )
-#define u32tobuf( p, a) ulongtobuf( (p), (a) )
-
-
-/**************************************************
- ************** read and write helpers ************
- **************************************************/
+static int pending_check_trustdb;
 
-static void
-fwrite_8(FILE *fp, byte a)
-{
-    if( putc( a & 0xff, fp ) == EOF )
-       log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
-}
+static int validate_keys (int interactive);
 
+\f
+/**********************************************
+ ************* some helpers *******************
+ **********************************************/
 
-static void
-fwrite_32( FILE*fp, ulong a)
+static struct key_item *
+new_key_item (void)
 {
-    putc( (a>>24) & 0xff, fp );
-    putc( (a>>16) & 0xff, fp );
-    putc( (a>> 8) & 0xff, fp );
-    if( putc( a & 0xff, fp ) == EOF )
-       log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
+  struct key_item *k;
+  
+  k = xcalloc (1,sizeof *k);
+  return k;
 }
 
 static void
-fwrite_zeros( FILE *fp, size_t n)
+release_key_items (struct key_item *k)
 {
-    while( n-- )
-       if( putc( 0, fp ) == EOF )
-           log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
-}
-
-
-/**************************************************
- ************** read and write stuff **************
- **************************************************/
+  struct key_item *k2;
 
+  for (; k; k = k2)
+    {
+      k2 = k->next;
+      xfree (k->trust_regexp);
+      xfree (k);
+    }
+}
 
-/****************
- * Create a new trustdb
+/*
+ * 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 void
-create_db( const char *fname )
+static KeyHashTable 
+new_key_hash_table (void)
 {
-    FILE *fp;
-
-    fp =fopen( fname, "w" );
-    if( !fp )
-       log_fatal("can't create %s: %s\n", fname, strerror(errno) );
-    fwrite_8( fp, 1 );
-    fwrite_8( fp, 'g' );
-    fwrite_8( fp, '1' );
-    fwrite_8( fp, '0' );
-    fwrite_8( fp, 1 ); /* version */
-    fwrite_zeros( fp, 3 ); /* reserved */
-    fwrite_32( fp, 0 ); /* not locked */
-    fwrite_32( fp, make_timestamp() ); /* created */
-    fwrite_32( fp, 0 ); /* not yet modified */
-    fwrite_32( fp, 0 ); /* not yet validated*/
-    fwrite_32( fp, 0 ); /* local-id-counter (not used) */
-    fwrite_8( fp, 3 ); /* marginals needed */
-    fwrite_8( fp, 1 ); /* completes needed */
-    fwrite_8( fp, 4 ); /* max_cet_depth */
-    fwrite_zeros( fp, 9 ); /* filler */
-    fclose(fp);
-}
+  struct key_item **tbl;
 
-static void
-open_db()
-{
-    TRUSTREC rec;
-    assert( db_fd == -1 );
-
-    db_fd = open( db_name, O_RDWR );
-    if( db_fd == -1 )
-       log_fatal("can't open %s: %s\n", db_name, strerror(errno) );
-    if( read_record( 0, &rec ) )
-       log_fatal("TrustDB %s is invalid\n", db_name );
-    /* fixme: check ->locked and other stuff */
+  tbl = xcalloc (1,1024 * sizeof *tbl);
+  return tbl;
 }
 
-
-/****************
- * read the record with number recnum
- * returns: -1 on error, 0 on success
- */
-static int
-read_record( ulong recnum, TRUSTREC *rec )
+static void
+release_key_hash_table (KeyHashTable tbl)
 {
-    byte buf[TRUST_RECORD_LEN], *p;
-    int rc = 0;
-    int n, i;
-
-    if( db_fd == -1 )
-       open_db();
-    if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
-       log_error("trustdb: lseek failed: %s\n", strerror(errno) );
-       return G10ERR_READ_FILE;
-    }
-    n = read( db_fd, buf, TRUST_RECORD_LEN);
-    if( !n ) {
-       return -1; /* eof */
-    }
-    else if( n != TRUST_RECORD_LEN ) {
-       log_error("trustdb: read failed (n=%d): %s\n", n, strerror(errno) );
-       return G10ERR_READ_FILE;
-    }
-    p = buf;
-    rec->rectype = *p++;
-    rec->reserved = *p++;
-    switch( rec->rectype ) {
-      case 0:  /* unused record */
-       break;
-      case 1: /* version record */
-       rec->r.version.magic[0] = *p++;
-       rec->r.version.magic[1] = *p++;
-       rec->r.version.version  = *p++;
-       memcpy( rec->r.version.reserved, p, 3); p += 3;
-       rec->r.version.locked   = buftoulong(p); p += 4;
-       rec->r.version.created  = buftoulong(p); p += 4;
-       rec->r.version.modified = buftoulong(p); p += 4;
-       rec->r.version.validated= buftoulong(p); p += 4;
-       rec->r.version.local_id_counter = buftoulong(p); p += 4;
-       rec->r.version.marginals_needed = *p++;
-       rec->r.version.completes_needed = *p++;
-       rec->r.version.max_cert_depth = *p++;
-       if( recnum ) {
-           log_error("%s: version record with recnum %lu\n",
-                                                   db_name, (ulong)recnum );
-           rc = G10ERR_TRUSTDB;
-       }
-       if( rec->reserved != 'g' || rec->r.version.magic[0] != '1'
-                                 || rec->r.version.magic[1] != '0' ) {
-           log_error("%s: not a trustdb file\n", db_name );
-           rc = G10ERR_TRUSTDB;
-       }
-       if( rec->r.version.version != 1 ) {
-           log_error("%s: invalid file version %d\n",
-                                      db_name, rec->r.version.version );
-           rc = G10ERR_TRUSTDB;
-       }
-       break;
-      case 2:
-       rec->r.pubkey.local_id = buftoulong(p); p += 4;
-       rec->r.pubkey.keyid[0] = buftou32(p); p += 4;
-       rec->r.pubkey.keyid[1] = buftou32(p); p += 4;
-       rec->r.pubkey.pubkey_algo = *p++;
-       rec->r.pubkey.reserved = *p++;
-       memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20;
-       rec->r.pubkey.ownertrust = *p++;
-       if( rec->r.pubkey.local_id != recnum ) {
-           log_error("%s: pubkey local_id != recnum (%lu,%lu)\n",
-                                       db_name,
-                                       (ulong)rec->r.pubkey.local_id,
-                                       (ulong)recnum );
-           rc = G10ERR_TRUSTDB;
-       }
-       break;
-      case 3:
-       rec->r.cache.owner    = buftoulong(p); p += 4;
-       rec->r.cache.keyid[0] = buftou32(p); p += 4;
-       rec->r.cache.keyid[1] = buftou32(p); p += 4;
-       rec->r.cache.valid = *p++;
-       rec->r.cache.reserved = *p++;
-       memcpy(rec->r.cache.blockhash, p, 20); p += 20;
-       rec->r.cache.n_untrusted = *p++;
-       rec->r.cache.n_marginal = *p++;
-       rec->r.cache.n_fully = *p++;
-       rec->r.cache.trustlevel = *p++;
-       break;
-      case 4:
-      case 5:
-       rec->r.sigrec.owner   = buftoulong(p); p += 4;
-       rec->r.sigrec.chain   = buftoulong(p); p += 4;
-       for(i=0; i < SIGS_PER_RECORD; i++ ) {
-           rec->r.sigrec.sig[i].local_id = buftoulong(p); p += 4;
-           rec->r.sigrec.sig[i].flag = *p++;
-       }
-       break;
-      default:
-       log_error("%s: invalid record type %d at recnum %lu\n",
-                                       db_name, rec->rectype, (ulong)recnum );
-       rc = G10ERR_TRUSTDB;
-       break;
-    }
+  int i;
 
-    return rc;
+  if (!tbl)
+    return;
+  for (i=0; i < 1024; i++)
+    release_key_items (tbl[i]);
+  xfree (tbl);
 }
 
-/****************
- * Write the record at RECNUM
+/* 
+ * Returns: True if the keyID is in the given hash table
  */
 static int
-write_record( ulong recnum, TRUSTREC *rec )
+test_key_hash_table (KeyHashTable tbl, u32 *kid)
 {
-    byte buf[TRUST_RECORD_LEN], *p;
-    int rc = 0;
-    int i, n;
-
-    if( db_fd == -1 )
-       open_db();
-
-    memset(buf, 0, TRUST_RECORD_LEN);
-    p = buf;
-    *p++ = rec->rectype;
-    *p++ = rec->reserved;
-    switch( rec->rectype ) {
-      case 0:  /* unused record */
-       break;
-      case 1: /* version record */
-       BUG();
-       break;
-      case 2:
-       ulongtobuf(p, rec->r.pubkey.local_id); p += 4;
-       u32tobuf(p, rec->r.pubkey.keyid[0]); p += 4;
-       u32tobuf(p, rec->r.pubkey.keyid[1]); p += 4;
-       *p++ = rec->r.pubkey.pubkey_algo;
-       *p++ = rec->r.pubkey.reserved;
-       memcpy( p, rec->r.pubkey.fingerprint, 20); p += 20;
-       *p++ = rec->r.pubkey.ownertrust;
-       assert( rec->r.pubkey.local_id == recnum );
-       break;
-      case 3:
-       ulongtobuf(p, rec->r.cache.owner); p += 4;
-       u32tobuf(p, rec->r.cache.keyid[0]); p += 4;
-       u32tobuf(p, rec->r.cache.keyid[1]); p += 4;
-       *p++ = rec->r.cache.valid;
-       *p++ = rec->r.cache.reserved;
-       memcpy(p, rec->r.cache.blockhash, 20); p += 20;
-       *p++ = rec->r.cache.n_untrusted;
-       *p++ = rec->r.cache.n_marginal;
-       *p++ = rec->r.cache.n_fully;
-       *p++ = rec->r.cache.trustlevel;
-       break;
-      case 4:
-      case 5:
-       ulongtobuf(p, rec->r.sigrec.owner); p += 4;
-       ulongtobuf(p, rec->r.sigrec.chain); p += 4;
-       for(i=0; i < SIGS_PER_RECORD; i++ ) {
-           ulongtobuf(p, rec->r.sigrec.sig[i].local_id); p += 4;
-           *p++ = rec->r.sigrec.sig[i].flag;
-       }
-       break;
-      default:
-       BUG();
-    }
+  struct key_item *k;
 
-    if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
-       log_error("trustdb: lseek failed: %s\n", strerror(errno) );
-       return G10ERR_WRITE_FILE;
-    }
-    n = write( db_fd, buf, TRUST_RECORD_LEN);
-    if( n != TRUST_RECORD_LEN ) {
-       log_error("trustdb: write failed (n=%d): %s\n", n, strerror(errno) );
-       return G10ERR_WRITE_FILE;
-    }
-
-    return rc;
+  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;
 }
 
-
-
-/****************
- * create a new record and return its record number
+/*
+ * Add a new key to the hash table.  The key is identified by its key ID.
  */
-static ulong
-new_recnum()
+static void
+add_key_hash_table (KeyHashTable tbl, u32 *kid)
 {
-    off_t offset;
-    ulong recnum;
-    TRUSTREC rec;
-    int rc;
-
-    /* fixme: look for unused records */
-    offset = lseek( db_fd, 0, SEEK_END );
-    if( offset == -1 )
-       log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
-    recnum = offset / TRUST_RECORD_LEN;
-    assert(recnum); /* this is will never be the first record */
-
-    /* we must write a record, so that the next call to this function
-     * returns another recnum */
-    memset( &rec, 0, sizeof rec );
-    rec.rectype = 0; /* free record */
-    rc = write_record(recnum, &rec );
-    if( rc )
-       log_fatal("%s: failed to append a record: %s\n",
-                                           db_name, g10_errstr(rc));
-    return recnum ;
+  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;
 }
 
-/****************
- * Scan the trustdb for a record of type RECTYPE which matches PKC
- * The local_id is set to the correct value
+/*
+ * Release a key_array
  */
-static int
-scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
+static void
+release_key_array ( struct key_array *keys )
 {
-    ulong recnum;
-    u32 keyid[2];
-    byte *fingerprint;
-    size_t fingerlen;
-    int rc;
-
-    assert( rectype == 2 || rectype == 3 );
-
-    keyid_from_pkc( pkc, keyid );
-    fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
-    assert( fingerlen == 20 || fingerlen == 16 );
+    struct key_array *k;
 
-    for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
-       if( rec->rectype != rectype )
-           continue;
-       if( rec->rectype == 2 ) {
-           if( rec->r.pubkey.keyid[0] == keyid[0]
-               && rec->r.pubkey.keyid[1] == keyid[1]
-               && rec->r.pubkey.pubkey_algo == pkc->pubkey_algo
-               && !memcmp(rec->r.pubkey.fingerprint, fingerprint, fingerlen)
-             ) { /* found */
-               /* store the local_id */
-               if( pkc->local_id && pkc->local_id != recnum )
-                   log_error("%s: found record, but local_id from mem does "
-                             "not match recnum (%lu,%lu)\n", db_name,
-                                        (ulong)pkc->local_id, (ulong)recnum );
-               pkc->local_id = recnum;
-               return 0;
-           }
-       }
-       else
-           log_bug("not yet implemented\n");
+    if (keys) {
+        for (k=keys; k->keyblock; k++)
+            release_kbnode (k->keyblock);
+        xfree (keys);
     }
-    if( rc != -1 )
-       log_error("%s: scan_record_by_pkc failed: %s\n",db_name, g10_errstr(rc) );
-    return rc;
 }
 
-/****************
- * scan the DB for a record of type RECTYPE which can be localized
- * with LOCAL_ID
- */
-static int
-scan_record( ulong local_id, TRUSTREC *rec, int rectype, ulong *r_recnum )
-{
-    ulong recnum;
-    int rc;
+\f
+/*********************************************
+ **********  Initialization  *****************
+ *********************************************/
 
-    assert( rectype == 3 || rectype == 4 );
-
-    for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
-       if( rec->rectype != rectype )
-           continue;
-       if( rec->rectype == 34 ) {
-           if( rec->r.cache.owner == local_id ) { /* found */
-               *r_recnum = recnum;
-               return 0;
-           }
-       }
-       else if( rec->rectype == 4 ) {
-           if( rec->r.sigrec.owner == local_id ) { /* found */
-               *r_recnum = recnum;
-               return 0;
-           }
-       }
-       else
-           log_bug("not yet implemented\n");
-    }
-    if( rc != -1 )
-       log_error("%s: scan_record failed: %s\n",db_name, g10_errstr(rc) );
-    return rc;
-}
 
 
-static void
-dump_record( ulong rnum, TRUSTREC *rec, FILE *fp  )
+/*
+ * 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 )
 {
-    int i, any;
-
-    fprintf(fp, "trust record %lu, type=", rnum );
-
-    switch( rec->rectype ) {
-      case 0: fprintf(fp, "free\n");
-       break;
-      case 1: fprintf(fp, "version\n");
-       break;
-      case 2: fprintf(fp, "pubkey, keyid=%08lX, ownertrust=%02x\n",
-                  rec->r.pubkey.keyid[1], rec->r.pubkey.ownertrust );
-       break;
-      case 3: fprintf(fp, "cache\n");
-      case 4:
-      case 5:
-       fprintf(fp, "sigrec, owner=%lu, chain=%lu%s\n",
-                        rec->r.sigrec.owner, rec->r.sigrec.chain,
-                        rec->rectype == 4?"":" (extend)");
-       for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
-           if( rec->r.sigrec.sig[i].local_id ) {
-               if( !any ) {
-                   putc('\t', fp);
-                   any++;
-               }
-               fprintf(fp, "  %lu:%02x", rec->r.sigrec.sig[i].local_id,
-                                             rec->r.sigrec.sig[i].flag );
-           }
-       }
-       if( any )
-           putc('\n', fp);
-       break;
-      default:
-       fprintf(fp, "%d (unknown)\n", rec->rectype );
-       break;
-    }
+  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;
 }
 
-
-/****************
- * If we do not have a local_id in a signature packet, find the owner of
- * the signature packet in our trustdb or insert him into the trustdb
+/*
+ * Helper to add a key to the global list of ultimately trusted keys.
+ * Retruns: true = inserted, false = already in in list.
  */
 static int
-set_signature_packets_local_id( PKT_signature *sig )
+add_utk (u32 *kid)
 {
-    PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
-    TRUSTREC rec;
-    int rc;
-
-    rc = get_pubkey( pkc, sig->keyid );
-    if( rc)
-       goto leave;
-    if( !pkc->local_id ) {
-       rc = scan_record_by_pkc( pkc, &rec, 2 );
-       if( rc == -1 )
-           rc = insert_trust_record( pkc );
-       if( rc )
-           goto leave;
-       /* fixme: we should propagate the local_id to all copies of the PKC */
+  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;
+        }
     }
-    sig->local_id = pkc->local_id;
 
-  leave:
-    free_public_cert( pkc );
-    return rc;
+  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;
 }
 
 
-void
-list_trustdb( const char *username )
+/****************
+ * Verify that all our secret keys are usable and put them into the utk_list.
+ */
+static void
+verify_own_keys(void)
 {
-    TRUSTREC rec;
-
-    if( username ) {
-       PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
-       int rc;
-
-       if( (rc = get_pubkey_byname( pkc, username )) )
-           log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
-       else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && 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_sigs( pkc->local_id )) )
-           log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
-       free_public_cert( pkc );
+  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]);
+        }
     }
-    else {
-       ulong recnum;
-       int i;
-
-       printf("TrustDB: %s\n", db_name );
-       for(i=9+strlen(db_name); i > 0; i-- )
-           putchar('-');
-       putchar('\n');
-       for(recnum=0; !read_record( recnum, &rec); recnum++ )
-           dump_record( recnum, &rec, stdout );
-    }
-}
 
-void
-list_trust_path( int max_depth, const char *username )
-{
-    int rc;
-    int wipe=0;
-    int i;
-    TRUSTREC rec;
-    PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
-
-    if( max_depth < 0 ) {
-       wipe = 1;
-       max_depth = -max_depth;
+  /* 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]);
+        }
     }
 
-    if( (rc = get_pubkey_byname( pkc, username )) )
-       log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
-    else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && 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 {
-       TRUST_SEG_LIST tsl, tslist = NULL;
-
-       if( !qry_lid_table_flag( ultikey_table, pkc->local_id, NULL ) ) {
-           tslist = m_alloc( sizeof *tslist );
-           tslist->nseg = 1;
-           tslist->dup = 0;
-           tslist->seg[0].lid = pkc->local_id;
-           tslist->seg[0].trust = 0;
-           tslist->next = NULL;
-           rc = 0;
-       }
-       else {
-           LOCAL_ID_INFO *lids = new_lid_table();
-           TRUST_INFO stack[MAX_LIST_SIGS_DEPTH];
-
-           stack[0].lid = pkc->local_id;
-           stack[0].trust = 0;
-           rc = do_list_path( stack, 1, max_depth, lids, &tslist );
-           if( wipe ) { /* wipe out duplicates */
-               LOCAL_ID_INFO *work;
-
-               work = new_lid_table();
-               for( tsl=tslist; tsl; tsl = tsl->next ) {
-                   for(i=1; i < tsl->nseg-1; i++ ) {
-                       if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) {
-                           tsl->dup = 1; /* mark as duplicate */
-                           break;
-                       }
-                   }
-               }
-               release_lid_table(work);
-           }
-           release_lid_table(lids);
-       }
-       if( rc )
-           log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
-       rc = propagate_trust( tslist );
-       if( rc )
-           log_error("user '%s' trust problem: %s\n", username, g10_errstr(rc));
-       for(tsl = tslist; tsl; tsl = tsl->next ) {
-           int i;
-
-           if( tsl->dup )
-               continue;
-           printf("trust path:" );
-           for(i=0; i < tsl->nseg; i++ )
-               printf("  %lu/%02x", tsl->seg[i].lid, tsl->seg[i].trust );
-           putchar('\n');
-       }
-    }
 
-    free_public_cert( pkc );
+  /* release the helper table table */
+  release_key_items (user_utk_list);
+  user_utk_list = NULL;
+  return;
 }
 
-/****************
- * Walk throug the signatures of a public key.
- * The caller must provide a context structure, with all fields set
- * to zero, but the pubkeyid filed set to the requested pubkey;
- * 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
+\f
+/*********************************************
+ *********** TrustDB stuff *******************
+ *********************************************/
+
+/*
+ * Read a record but die if it does not exist
  */
-static int
-walk_sigrecs( SIGREC_CONTEXT *c )
+static void
+read_record (ulong recno, TRUSTREC *rec, int rectype )
 {
-    int rc=0;
-    TRUSTREC *r;
-    ulong rnum;
-
-    if( c->ctl.eof )
-       return -1;
-    r = &c->ctl.rec;
-    if( !r->rectype ) { /* this is the first call */
-       rc = scan_record( c->pubkey_id, r, 4, &rnum );
-       if( rc == -1 ) { /* no signature records */
-           c->ctl.eof = 1;
-           return -1;  /* return eof */
-       }
-       if( rc ) {
-           log_error("scan_record(sigrec) failed: %s\n", g10_errstr(rc));
-           c->ctl.eof = 1;
-           return rc;
-       }
-       c->ctl.index = 0;
+  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();
     }
-    /* enter loop to skip deleted sigs */
-    do {
-       if( c->ctl.index >= SIGS_PER_RECORD ) {
-           /* read the next record */
-           if( !r->r.sigrec.chain ) {
-               c->ctl.eof = 1;
-               return -1;  /* return eof */
-           }
-           rnum = r->r.sigrec.chain;
-           rc = read_record( rnum, r );
-           if( rc ) {
-               log_error("error reading next sigrec: %s\n", g10_errstr(rc));
-               c->ctl.eof = 1;
-               return rc;
-           }
-           if( r->r.sigrec.owner != c->pubkey_id ) {
-               log_error("chained sigrec %lu has a wrong owner\n", rnum );
-               c->ctl.eof = 1;
-               return G10ERR_TRUSTDB;
-           }
-           c->ctl.index = 0;
-       }
-    } while( !r->r.sigrec.sig[c->ctl.index++].local_id );
-    c->sig_id = r->r.sigrec.sig[c->ctl.index-1].local_id;
-    c->sig_flag = r->r.sigrec.sig[c->ctl.index-1].flag;
-    return 0;
 }
 
-/***********************************************
- ************* trust logic  *******************
- ***********************************************/
-
-static LOCAL_ID_INFO *
-new_lid_table(void)
+/*
+ * Write a record and die on error
+ */
+static void
+write_record (TRUSTREC *rec)
 {
-    return m_alloc_clear( 16 * sizeof(LOCAL_ID_INFO));
+  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
-release_lid_table( LOCAL_ID_INFO *tbl )
+do_sync(void)
 {
-    LOCAL_ID_INFO a, a2;
-    int i;
+    int rc = tdbio_sync ();
+    if(rc)
+      {
+        log_error (_("trustdb: sync failed: %s\n"), gpg_strerror (rc) );
+        g10_exit(2);
+      }
+}
 
-    for(i=0; i < 16; i++ ) {
-       for(a=tbl[i]; a; a = a2 ) {
-           a2 = a->next;
-           m_free(a);
-       }
+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";
     }
-    m_free(tbl);
 }
 
 /****************
- * Add a new item to the table or return 1 if we aread have this item
- * fixme: maybe its a good idea to tage items from an unused item list.
+ * Perform some checks over the trustdb
+ *  level 0: only open the db
+ *       1: used for initial program startup
  */
-static int
-ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
+int
+setup_trustdb( int level, const char *dbname )
 {
-    LOCAL_ID_INFO a;
-
-    for( a = tbl[lid & 0x0f]; a; a = a->next )
-       if( a->lid == lid )
-           return 1;
-    a = m_alloc( sizeof *a );
-    a->lid = lid;
-    a->flag = flag;
-    a->next = tbl[lid & 0x0f];
-    tbl[lid & 0x0f] = a;
+    /* just store the args */
+    if( trustdb_args.init )
+       return 0;
+    trustdb_args.level = level;
+    trustdb_args.dbname = dbname? xstrdup (dbname): NULL;
     return 0;
 }
 
-static int
-qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag )
+void
+init_trustdb()
 {
-    LOCAL_ID_INFO a;
-
-    for( a = tbl[lid & 0x0f]; a; a = a->next )
-       if( a->lid == lid ) {
-           if( flag )
-               *flag = a->flag;
-           return 0;
+  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;
        }
-    return -1;
-}
 
-static void
-upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
-{
-    LOCAL_ID_INFO a;
+      if(opt.verbose)
+       log_info(_("using %s trust model\n"),trust_model_string());
+    }
 
-    for( a = tbl[lid & 0x0f]; a; a = a->next )
-       if( a->lid == lid ) {
-           a->flag = flag;
-           return;
-       }
-    BUG();
+  if((opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+     && !tdbio_db_matches_options())
+    pending_check_trustdb=1;
 }
 
 
 
+\f
+/***********************************************
+ ************* Print helpers   ****************
+ ***********************************************/
 
+/****************
+ * This function returns a letter for a trustvalue  Trust flags
+ * are ignore.
+ */
 static int
-keyid_from_local_id( ulong lid, u32 *keyid )
+trust_letter (unsigned int value)
 {
-    TRUSTREC rec;
-    int rc;
-
-    rc = read_record( lid, &rec );
-    if( rc ) {
-       log_error("error reading record with local_id %lu: %s\n",
-                                                   lid, g10_errstr(rc));
-       return G10ERR_TRUSTDB;
+  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 '?';
     }
-    if( rec.rectype != 2 ) {
-       log_error("record with local_id %lu is not a pubkey record\n", lid);
-       return G10ERR_TRUSTDB;
+}
+
+/* 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";
     }
-    keyid[0] = rec.r.pubkey.keyid[0];
-    keyid[1] = rec.r.pubkey.keyid[1];
-    return 0;
 }
 
+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;
+}
 
 /****************
- * Verify, that all our public keys are in the trustDB.
+ * 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
  */
-static int
-verify_own_certs()
+void
+check_trustdb ()
 {
-    int rc;
-    void *enum_context = NULL;
-    PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
-    PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
-    u32 keyid[2];
-
-    while( !(rc=enum_secret_keys( &enum_context, skc) ) ) {
-       /* fixed: to be sure that it is a secret key of our own,
-        *        we should check it, but this needs a passphrase
-        *        for every key and this boring for the user.
-        *        Solution:  Sign the secring and the trustring
-        *                   and verify this signature during
-        *                   startup
-        */
-
-       keyid_from_skc( skc, keyid );
-
-       if( DBG_TRUST )
-           log_debug("checking secret key %08lX\n", (ulong)keyid[1] );
-
-       /* look wether we can access the public key of this secret key */
-       rc = get_pubkey( pkc, keyid );
-       if( rc ) {
-           log_error("keyid %08lX: secret key without public key\n",
-                                                           (ulong)keyid[1] );
-           goto leave;
-       }
-       if( cmp_public_secret_cert( pkc, skc ) ) {
-           log_error("keyid %08lX: secret and public key don't match\n",
-                                                           (ulong)keyid[1] );
-           rc = G10ERR_GENERAL;
-           goto leave;
-       }
-
-       /* make sure that the pubkey is in the trustdb */
-       rc = query_trust_record( pkc );
-       if( rc == -1 ) { /* put it into the trustdb */
-           rc = insert_trust_record( pkc );
-           if( rc ) {
-               log_error("keyid %08lX: can't put it into the trustdb\n",
-                                                           (ulong)keyid[1] );
-               goto leave;
+  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;
            }
-       }
-       else if( rc ) {
-           log_error("keyid %08lX: query record failed\n", (ulong)keyid[1] );
-           goto leave;
 
+         if (scheduled > make_timestamp ())
+           {
+             log_info (_("next trustdb check due at %s\n"),
+                       strtimestamp (scheduled));
+             return;
+           }
        }
 
-       if( DBG_TRUST )
-           log_debug("putting %08lX(%lu) into ultikey_table\n",
-                                   (ulong)keyid[1], pkc->local_id );
-       if( ins_lid_table_item( ultikey_table, pkc->local_id, 0 ) )
-           log_error("keyid %08lX: already in ultikey_table\n",
-                                                       (ulong)keyid[1]);
+      validate_keys (0);
+    }
+  else
+    log_info (_("no need for a trustdb check with \"%s\" trust model\n"),
+             trust_model_string());
+}
 
 
-       release_secret_cert_parts( skc );
-       release_public_cert_parts( pkc );
-    }
-    if( rc != -1 )
-       log_error("enum_secret_keys failed: %s\n", g10_errstr(rc) );
-    else
-       rc = 0;
-
-  leave:
-    free_secret_cert( skc );
-    free_public_cert( pkc );
-    return rc;
+/*
+ * 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());
 }
 
-static void
-print_user_id( const char *text, u32 *keyid )
+void
+revalidation_mark (void)
 {
-    char *p;
-    size_t n;
+  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;
+}
 
-    p = get_user_id( keyid, &n );
-    if( *text ) {
-       fputs( text, stdout);
-       putchar(' ');
-    }
-    putchar('\"');
-    print_string( stdout, p, n );
-    putchar('\"');
-    putchar('\n');
-    m_free(p);
+int
+trustdb_pending_check(void)
+{
+  return pending_check_trustdb;
 }
 
-/* (a non-recursive algorithm would be easier) */
-static int
-do_list_sigs( ulong root, ulong pubkey, int depth,
-             LOCAL_ID_INFO *lids, unsigned *lineno )
+\f
+/***********************************************
+ ***********  Ownertrust et al. ****************
+ ***********************************************/
+
+static int 
+read_trust_record (PKT_public_key *pk, TRUSTREC *rec)
 {
-    SIGREC_CONTEXT sx;
-    int rc;
-    u32 keyid[2];
-
-    memset( &sx, 0, sizeof sx );
-    sx.pubkey_id = pubkey;
-    for(;;) {
-       rc = walk_sigrecs( &sx );
-       if( rc )
-           break;
-       rc = keyid_from_local_id( sx.sig_id, keyid );
-       if( rc ) {
-           printf("%6u: %*s????????(%lu:%02x)\n", *lineno, depth*4, "",
-                                                  sx.sig_id, sx.sig_flag );
-           ++*lineno;
-       }
-       else {
-           printf("%6u: %*s%08lX(%lu:%02x) ", *lineno, depth*4, "",
-                             (ulong)keyid[1], sx.sig_id, sx.sig_flag );
-           /* check wether we already checked this pubkey */
-           if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
-               print_user_id("[ultimately trusted]", keyid);
-               ++*lineno;
-           }
-           else if( sx.sig_id == pubkey ) {
-               printf("[self-signature]\n");
-               ++*lineno;
-           }
-           else if( sx.sig_id == root ) {
-               printf("[closed]\n");
-               ++*lineno;
-           }
-           else if( ins_lid_table_item( lids, sx.sig_id, *lineno ) ) {
-               unsigned refline;
-               qry_lid_table_flag( lids, sx.sig_id, &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_id, depth+1, lids, lineno );
-               if( rc )
-                   break;
-           }
-       }
+  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; 
     }
-    return rc==-1? 0 : 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;
 }
 
 /****************
- * List all signatures of a public key
+ * Return the assigned ownertrust value for the given public key.
+ * The key should be the primary key.
  */
-static int
-list_sigs( ulong pubkey_id )
+unsigned int 
+get_ownertrust ( PKT_public_key *pk)
 {
-    int rc;
-    u32 keyid[2];
-    LOCAL_ID_INFO *lids;
-    unsigned lineno = 1;
-
-    rc = keyid_from_local_id( pubkey_id, keyid );
-    if( rc ) {
-       log_error("Hmmm, no pubkey record for local_id %lu\n", pubkey_id);
-       return rc;
+  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 */
     }
-    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);
-    return rc;
+
+  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
-do_list_path( TRUST_INFO *stack, int depth, int max_depth,
-             LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist )
+get_ownertrust_with_min (PKT_public_key *pk)
 {
-    SIGREC_CONTEXT sx;
-    unsigned last_depth;
-    int rc;
-
-    assert(depth);
-
-    /*printf("%2lu/%d: scrutinizig\n", stack[depth-1], depth);*/
-    if( depth >= max_depth || depth >= MAX_LIST_SIGS_DEPTH-1 ) {
-       /*printf("%2lu/%d: to deeply nested\n", stack[depth-1], depth);*/
-       return 0;
+  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;
     }
-    memset( &sx, 0, sizeof sx );
-    sx.pubkey_id = stack[depth-1].lid;
-    while( !(rc = walk_sigrecs( &sx )) ) {
-       TRUST_SEG_LIST tsl, t2, tl;
-       int i;
-
-       stack[depth].lid = sx.sig_id;
-       stack[depth].trust = 0;
-       if( qry_lid_table_flag( lids, sx.sig_id, &last_depth) ) {
-           /*printf("%2lu/%d: marked\n", sx.sig_id, depth );*/
-           ins_lid_table_item( lids, sx.sig_id, depth);
-           last_depth = depth;
-       }
-       else if( depth  < last_depth ) {
-           /*printf("%2lu/%d: last_depth=%u - updated\n", sx.sig_id, depth, last_depth);*/
-           last_depth = depth;
-           upd_lid_table_flag( lids, sx.sig_id, depth);
-       }
 
-       if( last_depth < depth )
-           /*printf("%2lu/%d: already visited\n", sx.sig_id, depth)*/;
-       else if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
-           /* found end of path; store it, ordered by path length */
-           tsl = m_alloc( sizeof *tsl + depth*sizeof(TRUST_INFO) );
-           tsl->nseg = depth+1;
-           tsl->dup = 0;
-           for(i=0; i <= depth; i++ )
-               tsl->seg[i] = stack[i];
-           for(t2=*tslist,tl=NULL; t2; tl=t2, t2 = t2->next )
-               if( depth < t2->nseg )
-                   break;
-           if( !tl ) {
-               tsl->next = t2;
-               *tslist = tsl;
-           }
-           else {
-               tsl->next = t2;
-               tl->next = tsl;
-           }
-           /*putchar('.'); fflush(stdout);*/
-           /*printf("%2lu/%d: found\n", sx.sig_id, depth);*/
-       }
-       else {
-           rc = do_list_path( stack, depth+1, max_depth, lids, tslist);
-           if( rc && rc != -1 )
-               break;
-       }
-    }
-    return rc==-1? 0 : rc;
+  return otrust;
 }
 
-
-
-/****************
- * Check all the sigs of the given keyblock and mark them
- * as checked.
+/*
+ * Same as get_ownertrust but return a trust letter instead of an
+ * value.  This takes the minimum ownertrust value into account.
  */
-static int
-check_sigs( KBNODE keyblock, int *selfsig_okay )
+int
+get_ownertrust_info (PKT_public_key *pk)
 {
-    KBNODE kbctx;
-    KBNODE node;
-    int rc;
-
-    *selfsig_okay = 0;
-    for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
-       if( node->pkt->pkttype == PKT_SIGNATURE
-           && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
-           int selfsig;
-           rc = check_key_signature( keyblock, node, &selfsig );
-           if( !rc ) {
-               if( selfsig ) {
-                   node->flag |= 2; /* mark signature valid */
-                   *selfsig_okay = 1;
-               }
-               else
-                   node->flag |= 1; /* mark signature valid */
-           }
-           if( DBG_TRUST )
-               log_debug("trustdb: sig from %08lX: %s\n",
-                               (ulong)node->pkt->pkt.signature->keyid[1],
-                                                   g10_errstr(rc) );
-       }
-    }
-    return 0;
+  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));
+}
 
-/****************
- * If we do not have sigrecs for the given key, build them and write them
- * to the trustdb
+/*
+ * Set the trust value of the given public key to the new value.
+ * The key should be a primary one.
  */
-static int
-build_sigrecs( ulong pubkeyid )
+void
+update_ownertrust (PKT_public_key *pk, unsigned int new_trust )
 {
-    TRUSTREC rec, rec2;
-    PUBKEY_FIND_INFO finfo=NULL;
-    KBPOS kbpos;
-    KBNODE keyblock = NULL;
-    KBNODE kbctx;
-    KBNODE node;
-    int rc=0;
-    int i, selfsig;
-    ulong rnum, rnum2;
-
-    if( DBG_TRUST )
-       log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid );
-
-    /* get the keyblock */
-    if( (rc=read_record( pubkeyid, &rec )) ) {
-       log_error("build_sigrecs: can't read pubkey record\n");
-       goto leave;
+  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 ();
+        }
     }
-    finfo = m_alloc_clear( sizeof *finfo );
-    finfo->keyid[0] = rec.r.pubkey.keyid[0];
-    finfo->keyid[1] = rec.r.pubkey.keyid[1];
-    finfo->pubkey_algo = rec.r.pubkey.pubkey_algo;
-    memcpy( finfo->fingerprint, rec.r.pubkey.fingerprint, 20);
-    rc = find_keyblock( finfo, &kbpos );
-    if( rc ) {
-       log_error("build_sigrecs: find_keyblock failed\n" );
-       goto leave;
+  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;
     }
-    rc = read_keyblock( &kbpos, &keyblock );
-    if( rc ) {
-       log_error("build_sigrecs: read_keyblock failed\n" );
-       goto leave;
+  else 
+    {
+      tdbio_invalid ();
     }
-    /* check all key signatures */
-    rc = check_sigs( keyblock, &selfsig );
-    if( rc ) {
-       log_error("build_sigrecs: check_sigs failed\n" );
-       goto leave;
+}
+
+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;
     }
-    if( !selfsig ) {
-       log_error("build_sigrecs: self-certificate missing\n" );
-       rc = G10ERR_BAD_CERT;
-       goto leave;
+
+  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 ();
+    }
+}
 
-    /* valid key signatures are now marked; we can now build the
-     * sigrecs */
-    memset( &rec, 0, sizeof rec );
-    rec.rectype = 4;
-    i = 0;
-    rnum = rnum2 = 0;
-    for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
-       if( node->flag & 1 ) {
-           assert( node->pkt->pkttype == PKT_SIGNATURE );
-           if( !node->pkt->pkt.signature->local_id )  {
-               /* the next function should always succeed, because
-                * we have already checked the signature, and for this
-                * it was necessary to have the pubkey. The only reason
-                * this can fail are I/o erros of the trustdb. */
-               rc = set_signature_packets_local_id( node->pkt->pkt.signature );
-               if( rc )
-                   log_fatal("set_signature_packets_local_id failed: %s\n",
-                                                             g10_errstr(rc));
-           }
-           if( i == SIGS_PER_RECORD ) {
-               /* write the record */
-               rnum = new_recnum();
-               if( rnum2 ) { /* write the stored record */
-                   rec2.r.sigrec.owner = pubkeyid;
-                   rec2.r.sigrec.chain = rnum; /* the next record number */
-                   rc = write_record( rnum2, &rec2 );
-                   if( rc ) {
-                       log_error("build_sigrecs: write_record failed\n" );
-                       goto leave;
-                   }
-               }
-               rec2 = rec;
-               rnum2 = rnum;
-               memset( &rec, 0, sizeof rec );
-               rec.rectype = 5;
-               i = 0;
-           }
-           rec.r.sigrec.sig[i].local_id = node->pkt->pkt.signature->local_id;
-           rec.r.sigrec.sig[i].flag = 0;
-           i++;
+/* 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;
+        }
     }
-    if( i || rnum2 ) {
-       /* write the record */
-       rnum = new_recnum();
-       if( rnum2 ) { /* write the stored record */
-           rec2.r.sigrec.owner = pubkeyid;
-           rec2.r.sigrec.chain = rnum;
-           rc = write_record( rnum2, &rec2 );
-           if( rc ) {
-               log_error("build_sigrecs: write_record failed\n" );
-               goto leave;
-           }
-       }
-       if( i ) { /* write the pending record */
-           rec.r.sigrec.owner = pubkeyid;
-           rec.r.sigrec.chain = 0;
-           rc = write_record( rnum, &rec );
-           if( rc ) {
-               log_error("build_sigrecs: write_record failed\n" );
-               goto leave;
-           }
-       }
+  else if (rc != -1)
+    {
+      tdbio_invalid ();
     }
-
-  leave:
-    m_free( finfo );
-    release_kbnode( keyblock );
-    if( DBG_TRUST )
-       log_debug("trustdb: build_sigrecs: %s\n", g10_errstr(rc) );
-    return rc;
+  return 0;
 }
 
-/****************
- * Make a list of trust paths
+/* 
+ * Note: Caller has to do a sync 
  */
-static int
-make_tsl( ulong pubkey_id, TRUST_SEG_LIST *ret_tslist )
+static void
+update_validity (PKT_public_key *pk, PKT_user_id *uid,
+                 int depth, int validity)
 {
-    int i, rc;
-    LOCAL_ID_INFO *lids = new_lid_table();
-    TRUST_INFO stack[MAX_LIST_SIGS_DEPTH];
-    TRUST_SEG_LIST tsl, tslist;
-    int max_depth = 4;
-
-    tslist = *ret_tslist = NULL;
-
-    if( !qry_lid_table_flag( ultikey_table, pubkey_id, NULL ) ) {
-       tslist = m_alloc( sizeof *tslist );
-       tslist->nseg = 1;
-       tslist->dup = 0;
-       tslist->seg[0].lid = pubkey_id;
-       tslist->seg[0].trust = 0;
-       tslist->next = NULL;
-       rc = 0;
+  TRUSTREC trec, vrec;
+  int rc;
+  ulong recno;
+
+  namehash_from_uid(uid);
+
+  rc = read_trust_record (pk, &trec);
+  if (rc && rc != -1)
+    {
+      tdbio_invalid ();
+      return;
     }
-    else {
-       stack[0].lid = pubkey_id;
-       stack[0].trust = 0;
-       rc = do_list_path( stack, 1, max_depth, lids, &tslist );
+  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( !rc ) { /* wipe out duplicates */
-       LOCAL_ID_INFO *work = new_lid_table();
-       for( tsl=tslist; tsl; tsl = tsl->next ) {
-           for(i=1; i < tsl->nseg-1; i++ ) {
-               if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) {
-                   tsl->dup = 1; /* mark as duplicate */
-                   break;
-               }
-           }
-       }
-       release_lid_table(work);
-       *ret_tslist = tslist;
+
+  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;
     }
-    else
-       ; /* FIXME: release tslist */
-    release_lid_table(lids);
-    return rc;
+  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);
 }
 
 
-/****************
- * Given a trust segment list tslist, walk over all paths and fill in
- * the trust information for each segment.  What this function does is
- * to assign a trustvalue to the first segment (which is the requested key)
- * of each path.
- *
- * FIXME: We have to do more thinks here. e.g. we should never increase
- *       the trust value.
- *
- * Do not do it for duplicates.
- */
+/* reset validity for all user IDs.  Caller must sync. */
 static int
-propagate_trust( TRUST_SEG_LIST tslist )
+clear_validity (PKT_public_key *pk)
 {
-    int i, rc;
-    unsigned trust;
-    TRUST_SEG_LIST tsl;
-
-    for(tsl = tslist; tsl; tsl = tsl->next ) {
-       if( tsl->dup )
-           continue;
-       assert( tsl->nseg );
-       /* the last segment is always a ultimately trusted one, so we can
-        * assign a fully trust to the next one */
-       i = tsl->nseg-1;
-       tsl->seg[i].trust = TRUST_ULTIMATE;
-       trust = TRUST_FULLY;
-       for(i-- ; i >= 0; i-- ) {
-           tsl->seg[i].trust = trust;
-           if( i > 0 ) {
-               /* get the trust of this pubkey */
-               rc = get_ownertrust( tsl->seg[i].lid, &trust );
-               if( rc )
-                   return rc;
-           }
-       }
+  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);
 
-/****************
- * we have the pubkey record but nothing more is known
+  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. 
  */
-static int
-do_check( ulong pubkeyid, unsigned *trustlevel )
+unsigned int
+get_validity (PKT_public_key *pk, PKT_user_id *uid)
 {
-    int i, rc=0;
-    ulong rnum;
-    TRUSTREC rec;
-    TRUST_SEG_LIST tsl, tsl2, tslist;
-    int marginal, fully;
-    int fully_needed = 4;
-    int marginal_needed = 6;
-
-    *trustlevel = TRUST_UNDEFINED;
-
-    /* verify the cache */
-
-    /* do we have sigrecs */
-    rc = scan_record( pubkeyid, &rec, 4, &rnum );
-    if( rc == -1 ) { /* no sigrecs, so build them */
-       rc = build_sigrecs( pubkeyid );
-       if( !rc ) /* and read again */
-           rc = scan_record( pubkeyid, &rec, 4, &rnum );
+  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);
+            }
+        }
     }
-    if( rc )
-       return rc;  /* error while looking for sigrec or building sigrecs */
-
-    /* fixme: take it from the cache if it is valid */
-
-    /* Make a list of all possible trust-paths */
-    rc = make_tsl( pubkeyid, &tslist );
-    if( rc )
-       return rc;
-    rc = propagate_trust( tslist );
-    if( rc )
-       return rc;
-    for(tsl = tslist; tsl; tsl = tsl->next ) {
-       if( tsl->dup )
-           continue;
 
-       log_debug("tslist segs:" );
-       for(i=0; i < tsl->nseg; i++ )
-           fprintf(stderr, "  %lu/%02x", tsl->seg[i].lid, tsl->seg[i].trust );
-       putc('\n',stderr);
+  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;
     }
 
-    /* and look wether there is a trusted path.
-     * We only have to look at the first segment, because
-     * propagate_trust has investigated all other segments */
-    marginal = fully = 0;
-    for(tsl = tslist; tsl; tsl = tsl->next ) {
-       if( tsl->dup )
-           continue;
-       if( tsl->seg[0].trust == TRUST_ULTIMATE ) {
-           *trustlevel = TRUST_ULTIMATE; /* our own key */
-           break;
+  /* 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;
+           }
        }
-       if( tsl->seg[0].trust == TRUST_FULLY ) {
-           marginal++;
-           fully++;
+      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);
        }
-       else if( tsl->seg[0].trust == TRUST_MARGINAL )
-           marginal++;
 
-       if( fully >= fully_needed ) {
-           *trustlevel = TRUST_FULLY;
-           break;
-       }
+      recno = vrec.r.valid.next;
     }
-    if( !tsl && marginal >= marginal_needed )
-       *trustlevel = TRUST_MARGINAL;
-
-    /* cache the tslist */
-    if( last_trust_web_key ) {
-       for( tsl = last_trust_web_tslist; tsl; tsl = tsl2 ) {
-           tsl2 = tsl->next;
-           m_free(tsl);
-       }
+  
+  if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
+    {
+      validity |= TRUST_FLAG_DISABLED;
+      pk->is_disabled=2;
     }
-    last_trust_web_key = pubkeyid;
-    last_trust_web_tslist = tslist;
-    return 0;
+  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;
 }
 
-
-/*********************************************************
- ****************  API Interface  ************************
- *********************************************************/
-
-/****************
- * Perform some checks over the trustdb
- *  level 0: only open the db
- *       1: used for initial program startup
- */
 int
-init_trustdb( int level )
+get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
 {
-    int rc=0;
-
-    if( !ultikey_table )
-       ultikey_table = new_lid_table();
-
-    if( !level || level==1 ) {
-       char *fname = make_filename("~/.g10", "trustdb.g10", NULL );
-       if( access( fname, R_OK ) ) {
-           if( errno != ENOENT ) {
-               log_error("can't access %s: %s\n", fname, strerror(errno) );
-               m_free(fname);
-               return G10ERR_TRUSTDB;
-           }
-           if( level )
-               create_db( fname );
-       }
-       m_free(db_name);
-       db_name = fname;
+    int trustlevel;
 
-       if( !level )
-           return 0;
+    trustlevel = get_validity (pk, uid);
+    if( trustlevel & TRUST_FLAG_REVOKED )
+       return 'r';
+    return trust_letter ( trustlevel );
+}
 
-       /* we can verify a signature about our local data (secring and trustdb)
-        * in ~/.g10/ here */
-       rc = verify_private_data();
-       if( !rc ) {
-           /* verify, that our own certificates are in the trustDB
-            * or move them to the trustdb. */
-           rc = verify_own_certs();
+const char *
+get_validity_string (PKT_public_key *pk, PKT_user_id *uid)
+{
+  int trustlevel;
 
-           /* should we check wether there is no other ultimately trusted
-            * key in the database? */
+  trustlevel = get_validity (pk, uid);
+  if( trustlevel & TRUST_FLAG_REVOKED )
+    return _("revoked");
+  return trust_value_to_string(trustlevel);
+}
 
-       }
-    }
-    else
-       BUG();
+static void
+get_validity_counts (PKT_public_key *pk, PKT_user_id *uid)
+{
+  TRUSTREC trec, vrec;
+  ulong recno;
 
-    return rc;
-}
+  if(pk==NULL || uid==NULL)
+    BUG();
 
+  namehash_from_uid(uid);
 
-/****************
- * Get the trustlevel for this PKC.
- * Note: This does not ask any questions
- * Returns: 0 okay of an errorcode
- *
- * It operates this way:
- *  locate the pkc 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:
- *         Return with a trustlevel, saying that we do not have
- *         a trust record for it. The caller may use insert_trust_record()
- *         and then call this function here 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_cert *pkc, unsigned *r_trustlevel )
-{
-    TRUSTREC rec;
-    unsigned trustlevel = TRUST_UNKNOWN;
-    int rc=0;
-
-    if( DBG_TRUST )
-       log_info("check_trust() called.\n");
-
-    /* get the pubkey record */
-    if( pkc->local_id ) {
-       if( read_record( pkc->local_id, &rec ) ) {
-           log_error("check_trust: read record failed\n");
-           return G10ERR_TRUSTDB;
-       }
-    }
-    else { /* no local_id: scan the trustdb */
-       if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
-           log_error("check_trust: scan_record_by_pkc(2) failed: %s\n",
-                                                           g10_errstr(rc));
-           return rc;
-       }
-       else if( rc == -1 ) {
-           log_error("check_trust: pubkey not in TrustDB\n");
-           goto leave;
-       }
-    }
-    /* fixme: do some additional checks on the pubkey record */
+  uid->help_marginal_count=uid->help_full_count=0;
 
-    rc = do_check( pkc->local_id, &trustlevel );
-    if( rc ) {
-       log_error("check_trust: do_check failed: %s\n", g10_errstr(rc));
-       return rc;
-    }
+  init_trustdb ();
 
+  if(read_trust_record (pk, &trec)!=0)
+    return;
 
-  leave:
-    if( DBG_TRUST )
-       log_info("check_trust() returns trustlevel %04x.\n", trustlevel);
-    *r_trustlevel = trustlevel;
-    return 0;
-}
+  /* 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 dies not return the key itself or
- * the ultimate key.
+ * 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.
@@ -1609,212 +1189,942 @@ check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel )
  *  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 it's context.
+ *     so that it can free its context.
+ *
+ * Returns: -1 on EOF or the level of the returned LID
  */
 int
-enum_trust_web( void **context, ulong *lid )
+enum_cert_paths( void **context, ulong *lid,
+                unsigned *ownertrust, unsigned *validity )
 {
-    ENUM_TRUST_WEB_CONTEXT *c = *context;
-
-    if( !c ) { /* make a new context */
-       c = m_alloc_clear( sizeof *c );
-       *context = c;
-       if( *lid != last_trust_web_key )
-           log_bug("enum_trust_web: nyi\n");
-       c->tsl = last_trust_web_tslist;
-       c->index = 1;
-    }
-
-    if( !lid ) { /* free the context */
-       m_free( c );
-       *context = NULL;
-       return 0;
-    }
-
-    while( c->tsl ) {
-       if( !c->tsl->dup && c->index < c->tsl->nseg-1 ) {
-           *lid = c->tsl->seg[c->index].lid;
-           c->index++;
-           return 0;
-       }
-       c->index = 1;
-       c->tsl = c->tsl->next;
-    }
-    return -1; /* eof */
+    return -1;
 }
 
 
 /****************
- * Return the assigned ownertrust value for the given LID
+ * Print the current path
  */
-int
-get_ownertrust( ulong lid, unsigned *r_otrust )
+void
+enum_cert_paths_print( void **context, FILE *fp,
+                                      int refresh, ulong selected_lid )
 {
-    TRUSTREC rec;
+    return;
+}
+
 
-    if( read_record( lid, &rec ) ) {
-       log_error("get_ownertrust: read record failed\n");
-       return G10ERR_TRUSTDB;
+\f
+/****************************************
+ *********** 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( r_otrust )
-       *r_otrust = rec.r.pubkey.ownertrust;
-    return 0;
+  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;
 }
 
-int
-keyid_from_trustdb( ulong lid, u32 *keyid )
+
+static void
+mark_keyblock_seen (KeyHashTable tbl, KBNODE node)
 {
-    TRUSTREC rec;
+  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);
+      }
+}
 
-    if( read_record( lid, &rec ) ) {
-       log_error("keyid_from_trustdb: read record failed\n");
-       return G10ERR_TRUSTDB;
-    }
-    if( keyid ) {
-       keyid[0] = rec.r.pubkey.keyid[0];
-       keyid[1] = rec.r.pubkey.keyid[1];
+
+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');
+            }
+        }
     }
-    return 0;
-}
+}  
 
 
-int
-query_trust_record( PKT_public_cert *pkc )
+static void
+store_validation_status (int depth, KBNODE keyblock, KeyHashTable stored)
 {
-    TRUSTREC rec;
-    int rc=0;
+  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( pkc->local_id ) {
-       if( read_record( pkc->local_id, &rec ) ) {
-           log_error("query_trust_record: read record failed\n");
-           return G10ERR_TRUSTDB;
-       }
+  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;
     }
-    else { /* no local_id: scan the trustdb */
-       if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
-           log_error("query_trust_record: scan_record_by_pkc(2) failed: %s\n",
-                                                           g10_errstr(rc));
-           return rc;
-       }
-       else if( rc == -1 )
-           return rc;
+  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;
+            }
+        }
     }
-    return 0;
 }
 
+/* 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 *exp,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(exp, string, DBG_TRUST);
+#else
+  int ret;
+  regex_t pat;
+
+  if(regcomp(&pat,exp,REG_ICASE|REG_NOSUB|REG_EXTENDED)!=0)
+    return 0;
 
-/****************
- * Insert a trust record into the TrustDB
- * This function failes if this record already exists.
+  ret=regexec(&pat,string,0,NULL,0);
+
+  regfree(&pat);
+
+  if(DBG_TRUST)
+    log_debug("regexp \"%s\" on \"%s\": %s\n",exp,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.
  */
-int
-insert_trust_record( PKT_public_cert *pkc )
+static int
+validate_one_keyblock (KBNODE kb, struct key_item *klist,
+                       u32 curtime, u32 *next_expire)
 {
-    TRUSTREC rec;
-    u32 keyid[2];
-    ulong recnum;
-    byte *fingerprint;
-    size_t fingerlen;
-
-
-    if( pkc->local_id )
-       log_bug("pkc->local_id=%lu\n", (ulong)pkc->local_id );
-
-    keyid_from_pkc( pkc, keyid );
-    fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
-
-    /* FIXME: check that we do not have this record. */
-
-    recnum = new_recnum();
-    /* build record */
-    memset( &rec, 0, sizeof rec );
-    rec.rectype = 2; /* the pubkey record */
-    rec.r.pubkey.local_id = recnum;
-    rec.r.pubkey.keyid[0] = keyid[0];
-    rec.r.pubkey.keyid[1] = keyid[1];
-    rec.r.pubkey.pubkey_algo = pkc->pubkey_algo;
-    memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
-    rec.r.pubkey.ownertrust = 0;
-    if( write_record( recnum, &rec ) ) {
-       log_error("insert_trust_record: write failed\n");
-       return G10ERR_TRUSTDB;
+  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. -dshaw */
+
+      /* && node->pkt->pkt.user_id->created) */
+      if (node->pkt->pkttype == PKT_USER_ID)
+        {
+          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 0
+         /* If the selfsig is going to expire...  This is disabled as
+            we do count un-self-signed uids in the web of trust. */
+         if(uid->expiredate && uid->expiredate<*next_expire)
+           *next_expire = uid->expiredate;
+#endif
+          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;
+           }
+        }
     }
 
-    pkc->local_id = recnum;
+  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 0;
+  return any_signed;
 }
 
 
-int
-update_ownertrust( ulong lid, unsigned new_trust )
+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)
 {
-    TRUSTREC rec;
+  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;
+    }
 
-    if( read_record( lid, &rec ) ) {
-       log_error("update_ownertrust: read failed\n");
-       return G10ERR_TRUSTDB;
+  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;
     }
-    /* check keyid, fingerprint etc ? */
-    if( rec.rectype != 2 ) {
-       log_error("update_ownertrust: invalid record type\n");
-       return G10ERR_TRUSTDB;
+  
+  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;
     }
 
-    rec.r.pubkey.ownertrust = new_trust;
-    if( write_record( lid, &rec ) ) {
-       log_error("update_ownertrust: write failed\n");
-       return G10ERR_TRUSTDB;
+  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;
     }
 
-    return 0;
+  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);
 }
 
-
-int
-verify_private_data()
+/*
+ * 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;
-    char *sigfile = make_filename("~/.g10", "sig", NULL );
-
-    if( access( sigfile, R_OK ) ) {
-       if( errno != ENOENT ) {
-           log_error("can't access %s: %s\n", sigfile, strerror(errno) );
-           rc = G10ERR_TRUSTDB;
-           goto leave;
-       }
-       log_info("private data signature missing; creating ...\n");
-       rc = sign_private_data();
-       if( rc ) {
-           log_error("error creating %s: %s\n", sigfile, g10_errstr(rc) );
-           goto leave;
-       }
+  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;
     }
 
-    /* FIXME: verify this signature */
+  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 ();
+    }
 
-  leave:
-    m_free(sigfile);
-    return rc;
-}
+  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;
+           }
 
-int
-sign_private_data()
-{
-    int rc;
-    char *sigfile = make_filename("~/.g10", "sig", NULL );
-    char *secring = make_filename("~/.g10", "secring.g10", NULL );
-    STRLIST list = NULL;
+         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 */
+    }
 
-    add_to_strlist( &list, db_name );
-    add_to_strlist( &list, secring );
+ 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();
+       }
 
-    rc = sign_file( list, 1, NULL, 0, NULL, sigfile);
+      do_sync ();
+      pending_check_trustdb = 0;
+    }
 
-    m_free(sigfile);
-    m_free(secring);
-    free_strlist(list);
-    return rc;
+  return rc;
 }
-