See ChangeLog: Thu Jan 21 06:22:10 CET 1999 Werner Koch
[gnupg.git] / g10 / trustdb.c
index bb4942c..674240a 100644 (file)
@@ -1,14 +1,14 @@
 /* trustdb.c
  *     Copyright (C) 1998 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG 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.
  *
- * GNUPG 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.
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <ctype.h>
 #include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "packet.h"
 #include "main.h"
 #include "i18n.h"
+#include "tdbio.h"
 
+#if MAX_FINGERPRINT_LEN > 20
+  #error Must change structure of trustdb
+#endif
 
-#define TRUST_RECORD_LEN 40
-#define SIGS_PER_RECORD        ((TRUST_RECORD_LEN-10)/5)
-#define ITEMS_PER_HTBL_RECORD  ((TRUST_RECORD_LEN-2)/4)
-#define ITEMS_PER_HLST_RECORD  ((TRUST_RECORD_LEN-6)/5)
-#define MAX_LIST_SIGS_DEPTH  20
-
-
-#define RECTYPE_VER  1
-#define RECTYPE_DIR  2
-#define RECTYPE_KEY  3
-#define RECTYPE_CTL  4
-#define RECTYPE_SIG  5
-#define RECTYPE_HTBL 6
-#define RECTYPE_HLST 7
-
-
-struct trust_record {
-    int  rectype;
-    union {
-       struct {            /* version record: */
-           byte version;   /* should be 1 */
-           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   */
-           byte marginals_needed;
-           byte completes_needed;
-           byte max_cert_depth;
-       } ver;
-       struct {            /* directory record */
-           ulong local_id;
-           u32  keyid[2];
-           ulong keyrec;   /* recno of public key record */
-           ulong ctlrec;   /* recno of control record */
-           ulong sigrec;   /* recno of first signature record */
-           ulong link;     /* to next dir record */
-           byte no_sigs;   /* does not have sigature and checked */
-       } dir;
-       struct {            /* public key record */
-           ulong owner;
-           u32  keyid[2];
-           byte pubkey_algo;
-           byte fingerprint_len;
-           byte fingerprint[20];
-           byte ownertrust;
-       } key;
-       struct {            /* control record */
-           ulong owner;
-           byte blockhash[20];
-           byte trustlevel;   /* calculated trustlevel */
-       } ctl;
-       struct {            /* signature record */
-           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];
-       } sig;
-       struct {
-           ulong item[ITEMS_PER_HTBL_RECORD];
-       } htbl;
-       struct {
-           ulong chain;
-           struct {
-               byte hash;
-               ulong rnum;
-           } item[ITEMS_PER_HLST_RECORD];
-       } hlst;
-    } r;
+struct keyid_list {
+    struct keyid_list *next;
+    u32 keyid[2];
 };
-typedef struct trust_record TRUSTREC;
-
-typedef struct {
-    ulong     local_id;    /* localid of the pubkey */
-    ulong     sigrec;
-    ulong     sig_id;     /* returned signature id */
-    unsigned  sig_flag;    /* returned signature record flag */
-    struct {              /* internal data */
-       int init_done;
-       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;
+struct local_id_item {
+    struct local_id_item *next;
     ulong lid;
     unsigned flag;
 };
 
+struct local_id_table {
+    struct local_id_table *next; /* only used to keep a list of unused tables */
+    struct local_id_item *items[16];
+};
+
+
+typedef struct local_id_table *LOCAL_ID_TABLE;
+
 
 typedef struct trust_info TRUST_INFO;
 struct trust_info {
     ulong    lid;
-    unsigned trust;
+    byte     otrust; /* ownertrust (assigned trust) */
+    byte     trust;  /* calculated trust (validity) */
 };
 
-
 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 */
+    int  pathlen;
+    TRUST_INFO path[1];
 };
 
 
-typedef struct {
-    TRUST_SEG_LIST tsl;
-    int index;
-} ENUM_TRUST_WEB_CONTEXT;
+struct enum_cert_paths_ctx {
+   int init;
+   TRUST_SEG_LIST tsl_head;
+   TRUST_SEG_LIST tsl;
+   int idx;
+};
+
 
+struct recno_list_struct {
+    struct recno_list_struct *next;
+    ulong recno;
+    int type;
+};
+typedef struct recno_list_struct *RECNO_LIST;
 
-static void create_db( const char *fname );
-static void open_db(void);
-static void dump_record( ulong rnum, TRUSTREC *rec, FILE *fp );
-static int  read_record( ulong recnum, TRUSTREC *rec, int expected );
-static int  write_record( ulong recnum, TRUSTREC *rec );
-static ulong new_recnum(void);
-static int search_record( PKT_public_cert *pkc, TRUSTREC *rec );
-static int walk_sigrecs( SIGREC_CONTEXT *c, int create );
 
-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 int walk_sigrecs( SIGREC_CONTEXT *c );
 
-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 LOCAL_ID_TABLE new_lid_table(void);
+static void release_lid_table( LOCAL_ID_TABLE tbl );
+static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
+static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
 
+static void print_user_id( const char *text, u32 *keyid );
+static void sort_tsl_list( TRUST_SEG_LIST *trust_seg_list );
 static int list_sigs( ulong pubkey_id );
-static int build_sigrecs( ulong pubkeyid );
-static int propagate_trust( TRUST_SEG_LIST tslist );
-static int do_check( ulong pubkeyid, TRUSTREC *drec, unsigned *trustlevel );
+static int do_check( TRUSTREC *drec, unsigned *trustlevel );
+static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
 
-static int update_no_sigs( ulong lid, int no_sigs );
+static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig );
+static void upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
+                TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
+                TRUSTREC *urec, const byte *uidhash, int revoke );
 
-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 struct keyid_list *trusted_key_list;
 
-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) );
-}
+/* a table used to keep track of ultimately trusted keys
+ * which are the ones from our secrings and the trusted keys */
+static LOCAL_ID_TABLE ultikey_table;
 
+/* list of unused lid items and tables */
+static LOCAL_ID_TABLE unused_lid_tables;
+static struct local_id_item *unused_lid_items;
 
-static void
-fwrite_32( FILE*fp, ulong a)
-{
-    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) );
-}
 
-static void
-fwrite_zeros( FILE *fp, size_t n)
-{
-    while( n-- )
-       if( putc( 0, fp ) == EOF )
-           log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
-}
+#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
+                     (a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
 
 
+\f
 /**********************************************
- ************* list helpers *******************
+ ***********  record read write  **************
  **********************************************/
 
-static LOCAL_ID_INFO *
-new_lid_table(void)
+static void
+die_invalid_db()
 {
-    return m_alloc_clear( 16 * sizeof(LOCAL_ID_INFO));
+    log_error(_(
+       "The trustdb is corrupted; please run \"gpgm --fix-trustdb\".\n") );
+    g10_exit(2);
 }
 
+/****************
+ * Read a record but die if it does not exist
+ */
 static void
-release_lid_table( LOCAL_ID_INFO *tbl )
+read_record( ulong recno, TRUSTREC *rec, int rectype )
 {
-    LOCAL_ID_INFO a, a2;
-    int i;
-
-    for(i=0; i < 16; i++ ) {
-       for(a=tbl[i]; a; a = a2 ) {
-           a2 = a->next;
-           m_free(a);
-       }
-    }
-    m_free(tbl);
+    int rc = tdbio_read_record( recno, rec, rectype );
+    if( !rc )
+       return;
+    log_error(_("trust record %lu, req type %d: read failed: %s\n"),
+                                   recno, rectype,  g10_errstr(rc) );
+    die_invalid_db();
 }
 
+
 /****************
- * Add a new item to the table or return 1 if we already have this item
- * fixme: maybe it's a good idea to take items from an unused item list.
+ * Wirte a record but die on error
  */
-static int
-ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
+static void
+write_record( TRUSTREC *rec )
 {
-    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;
-    return 0;
+    int rc = tdbio_write_record( rec );
+    if( !rc )
+       return;
+    log_error(_("trust record %lu, type %d: write failed: %s\n"),
+                           rec->recnum, rec->rectype, g10_errstr(rc) );
+    die_invalid_db();
 }
 
-static int
-qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag )
+/****************
+ * Delete a record but die on error
+ */
+static void
+delete_record( ulong recno )
 {
-    LOCAL_ID_INFO a;
-
-    for( a = tbl[lid & 0x0f]; a; a = a->next )
-       if( a->lid == lid ) {
-           if( flag )
-               *flag = a->flag;
-           return 0;
-       }
-    return -1;
+    int rc = tdbio_delete_record( recno );
+    if( !rc )
+       return;
+    log_error(_("trust record %lu: delete failed: %s\n"),
+                                             recno, g10_errstr(rc) );
+    die_invalid_db();
 }
 
+/****************
+ * sync the db
+ */
 static void
-upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
+do_sync( )
 {
-    LOCAL_ID_INFO a;
-
-    for( a = tbl[lid & 0x0f]; a; a = a->next )
-       if( a->lid == lid ) {
-           a->flag = flag;
-           return;
-       }
-    BUG();
+    int rc = tdbio_sync();
+    if( !rc )
+       return;
+    log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
+    g10_exit(2);
 }
 
 
-/**************************************************
- ************** read and write stuff **************
- **************************************************/
-
+\f
+/**********************************************
+ ************* list helpers *******************
+ **********************************************/
 
 /****************
- * Create a new trustdb
+ * Insert a new item into a recno list
  */
 static void
-create_db( const char *fname )
+ins_recno_list( RECNO_LIST *head, ulong recno, int type )
 {
-    FILE *fp;
+    RECNO_LIST item = m_alloc( sizeof *item );
 
-    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, 'p' );
-    fwrite_8( fp, 'g' );
-    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 ); /* reserved */
-    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);
+    item->recno = recno;
+    item->type = type;
+    item->next = *head;
+    *head = item;
 }
 
-static void
-open_db()
+static RECNO_LIST
+qry_recno_list( RECNO_LIST list, ulong recno, int type )
 {
-    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, RECTYPE_VER ) )
-       log_fatal(_("TrustDB %s is invalid\n"), db_name );
-    /* fixme: check ->locked and other stuff */
+    for( ; list; list = list->next ) {
+       if( list->recno == recno && (!type || list->type == type) )
+           return list;
+    }
+    return NULL;
 }
 
 
 static void
-dump_record( ulong rnum, TRUSTREC *rec, FILE *fp  )
+rel_recno_list( RECNO_LIST *head )
 {
-    int i, any;
-
-    fprintf(fp, "trust record %lu, type=", rnum );
-
-    switch( rec->rectype ) {
-      case 0: fprintf(fp, "free\n");
-       break;
-      case RECTYPE_VER: fprintf(fp, "version\n");
-       break;
-      case RECTYPE_DIR:
-       fprintf(fp, "dir keyid=%08lX, key=%lu, ctl=%lu, sig=%lu",
-                   (ulong)rec->r.dir.keyid[1],
-                   rec->r.dir.keyrec, rec->r.dir.ctlrec, rec->r.dir.sigrec );
-       if( rec->r.dir.no_sigs == 1 )
-           fputs(", (none)", fp );
-       else if( rec->r.dir.no_sigs == 2 )
-           fputs(", (invalid)", fp );
-       else if( rec->r.dir.no_sigs == 3 )
-           fputs(", (revoked)", fp );
-       else if( rec->r.dir.no_sigs )
-           fputs(", (??)", fp );
-       putc('\n', fp);
-       break;
-      case RECTYPE_KEY: fprintf(fp,
-                   "key keyid=%08lX, own=%lu, ownertrust=%02x, fl=%d\n",
-                  (ulong)rec->r.key.keyid[1],
-                  rec->r.key.owner, rec->r.key.ownertrust,
-                  rec->r.key.fingerprint_len );
-       break;
-      case RECTYPE_CTL: fprintf(fp, "ctl\n");
-       break;
-      case RECTYPE_SIG:
-       fprintf(fp, "sigrec, owner=%lu, chain=%lu\n",
-                        rec->r.sig.owner, rec->r.sig.chain );
-       for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
-           if( rec->r.sig.sig[i].local_id ) {
-               if( !any ) {
-                   putc('\t', fp);
-                   any++;
-               }
-               fprintf(fp, "  %lu:%02x", rec->r.sig.sig[i].local_id,
-                                             rec->r.sig.sig[i].flag );
-           }
-       }
-       if( any )
-           putc('\n', fp);
-       break;
-      default:
-       fprintf(fp, "%d (unknown)\n", rec->rectype );
-       break;
+    RECNO_LIST r, r2;
+
+    for(r = *head; r; r = r2 ) {
+       r2 = r->next;
+       m_free(r);
     }
+    *head = NULL;
 }
 
-/****************
- * read the record with number recnum
- * returns: -1 on error, 0 on success
- */
-static int
-read_record( ulong recnum, TRUSTREC *rec, int expected )
+static LOCAL_ID_TABLE
+new_lid_table(void)
 {
-    byte buf[TRUST_RECORD_LEN], *p;
-    int rc = 0;
-    int n, i;
+    LOCAL_ID_TABLE a;
 
-    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;
+    a = unused_lid_tables;
+    if( a ) {
+       unused_lid_tables = a->next;
+       memset( a, 0, sizeof *a );
     }
-    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++;
-    if( expected && rec->rectype != expected ) {
-       log_error("%lu: read expected rec type %d, got %d\n",
-                   recnum, expected, rec->rectype );
-       return G10ERR_TRUSTDB;
-    }
-    p++;
-    switch( rec->rectype ) {
-      case 0:  /* unused record */
-       break;
-      case RECTYPE_VER: /* version record */
-       /* g10 was the original name */
-       if( memcmp(buf+1, "gpg", 3 ) && memcmp(buf+1, "g10", 3 ) ) {
-           log_error(_("%s: not a trustdb file\n"), db_name );
-           rc = G10ERR_TRUSTDB;
-       }
-       p += 2; /* skip magic */
-       rec->r.ver.version  = *p++;
-       rec->r.ver.locked   = buftoulong(p); p += 4;
-       rec->r.ver.created  = buftoulong(p); p += 4;
-       rec->r.ver.modified = buftoulong(p); p += 4;
-       rec->r.ver.validated= buftoulong(p); p += 4;
-       rec->r.ver.marginals_needed = *p++;
-       rec->r.ver.completes_needed = *p++;
-       rec->r.ver.max_cert_depth = *p++;
-       if( recnum ) {
-           log_error("%s: version record with recnum %lu\n",
-                                                   db_name, (ulong)recnum );
-           rc = G10ERR_TRUSTDB;
-       }
-       if( rec->r.ver.version != 1 ) {
-           log_error("%s: invalid file version %d\n",
-                                      db_name, rec->r.ver.version );
-           rc = G10ERR_TRUSTDB;
-       }
-       break;
-      case RECTYPE_DIR:   /*directory record */
-       rec->r.dir.local_id = buftoulong(p); p += 4;
-       rec->r.dir.keyid[0] = buftou32(p); p += 4;
-       rec->r.dir.keyid[1] = buftou32(p); p += 4;
-       rec->r.dir.keyrec   = buftoulong(p); p += 4;
-       rec->r.dir.ctlrec   = buftoulong(p); p += 4;
-       rec->r.dir.sigrec   = buftoulong(p); p += 4;
-       rec->r.dir.no_sigs = *p++;
-       if( rec->r.dir.local_id != recnum ) {
-           log_error("%s: dir local_id != recnum (%lu,%lu)\n",
-                                       db_name,
-                                       (ulong)rec->r.dir.local_id,
-                                       (ulong)recnum );
-           rc = G10ERR_TRUSTDB;
-       }
-       break;
-      case RECTYPE_KEY:   /* public key record */
-       rec->r.key.owner    = buftoulong(p); p += 4;
-       rec->r.dir.keyid[0] = buftou32(p); p += 4;
-       rec->r.dir.keyid[1] = buftou32(p); p += 4;
-       rec->r.key.pubkey_algo = *p++;
-       rec->r.key.fingerprint_len = *p++;
-       if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
-           rec->r.key.fingerprint_len = 20;
-       memcpy( rec->r.key.fingerprint, p, 20); p += 20;
-       rec->r.key.ownertrust = *p++;
-       break;
-      case RECTYPE_CTL:   /* control record */
-       rec->r.ctl.owner    = buftoulong(p); p += 4;
-       memcpy(rec->r.ctl.blockhash, p, 20); p += 20;
-       rec->r.ctl.trustlevel = *p++;
-       break;
-      case RECTYPE_SIG:
-       rec->r.sig.owner   = buftoulong(p); p += 4;
-       rec->r.sig.chain   = buftoulong(p); p += 4;
-       for(i=0; i < SIGS_PER_RECORD; i++ ) {
-           rec->r.sig.sig[i].local_id = buftoulong(p); p += 4;
-           rec->r.sig.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;
-    }
-
-    return rc;
+    else
+       a = m_alloc_clear( sizeof *a );
+    return a;
 }
 
-/****************
- * Write the record at RECNUM
- */
-static int
-write_record( ulong recnum, TRUSTREC *rec )
+static void
+release_lid_table( LOCAL_ID_TABLE tbl )
 {
-    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++;
-    switch( rec->rectype ) {
-      case 0:  /* unused record */
-       break;
-      case 1: /* version record */
-       BUG();
-       break;
-
-      case RECTYPE_DIR:   /*directory record */
-       ulongtobuf(p, rec->r.dir.local_id); p += 4;
-       u32tobuf(p, rec->r.key.keyid[0]); p += 4;
-       u32tobuf(p, rec->r.key.keyid[1]); p += 4;
-       ulongtobuf(p, rec->r.dir.keyrec); p += 4;
-       ulongtobuf(p, rec->r.dir.ctlrec); p += 4;
-       ulongtobuf(p, rec->r.dir.sigrec); p += 4;
-       *p++ = rec->r.dir.no_sigs;
-       assert( rec->r.dir.local_id == recnum );
-       break;
-
-      case RECTYPE_KEY:
-       ulongtobuf(p, rec->r.key.owner); p += 4;
-       u32tobuf(p, rec->r.key.keyid[0]); p += 4;
-       u32tobuf(p, rec->r.key.keyid[1]); p += 4;
-       *p++ = rec->r.key.pubkey_algo;
-       *p++ = rec->r.key.fingerprint_len;
-       memcpy( p, rec->r.key.fingerprint, 20); p += 20;
-       *p++ = rec->r.key.ownertrust;
-       break;
-
-      case RECTYPE_CTL:   /* control record */
-       ulongtobuf(p, rec->r.ctl.owner); p += 4;
-       memcpy(p, rec->r.ctl.blockhash, 20); p += 20;
-       *p++ = rec->r.ctl.trustlevel;
-       break;
-
-      case RECTYPE_SIG:
-       ulongtobuf(p, rec->r.sig.owner); p += 4;
-       ulongtobuf(p, rec->r.sig.chain); p += 4;
-       for(i=0; i < SIGS_PER_RECORD; i++ ) {
-           ulongtobuf(p, rec->r.sig.sig[i].local_id); p += 4;
-           *p++ = rec->r.sig.sig[i].flag;
-       }
-       break;
-      default:
-       BUG();
-    }
+    struct local_id_item *a, *a2;
+    int i;
 
-    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;
+    for(i=0; i < 16; i++ ) {
+       for(a=tbl->items[i]; a; a = a2 ) {
+           a2 = a->next;
+           a->next = unused_lid_items;
+           unused_lid_items = a;
+       }
     }
-
-    return rc;
+    tbl->next = unused_lid_tables;
+    unused_lid_tables = tbl;
 }
 
-
 /****************
- * create a new record and return its record number
+ * Add a new item to the table or return 1 if we already have this item
  */
-static ulong
-new_recnum()
+static int
+ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag )
 {
-    off_t offset;
-    ulong recnum;
-    TRUSTREC rec;
-    int rc;
+    struct local_id_item *a;
 
-    /* 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 ;
+    for( a = tbl->items[lid & 0x0f]; a; a = a->next )
+       if( a->lid == lid )
+           return 1;
+    a = unused_lid_items;
+    if( a )
+       unused_lid_items = a->next;
+    else
+       a = m_alloc( sizeof *a );
+    a->lid = lid;
+    a->flag = flag;
+    a->next = tbl->items[lid & 0x0f];
+    tbl->items[lid & 0x0f] = a;
+    return 0;
 }
 
-/****************
- * Search the trustdb for a key which matches PKC and return the dir record
- * The local_id of PKC is set to the correct value
- *
- * Note: To increase performance, we could use a index search here.
- */
 static int
-search_record( PKT_public_cert *pkc, TRUSTREC *rec )
+qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag )
 {
-    ulong recnum;
-    u32 keyid[2];
-    byte *fingerprint;
-    size_t fingerlen;
-    int rc;
-
-    keyid_from_pkc( pkc, keyid );
-    fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
-    assert( fingerlen == 20 || fingerlen == 16 );
-
-    for(recnum=1; !(rc=read_record( recnum, rec, 0)); recnum++ ) {
-       if( rec->rectype != RECTYPE_DIR )
-           continue;
-       if( rec->r.dir.keyid[0] == keyid[0]
-           && rec->r.dir.keyid[1] == keyid[1]){
-           TRUSTREC keyrec;
+    struct local_id_item *a;
 
-           if( read_record( rec->r.dir.keyrec, &keyrec, RECTYPE_KEY ) ) {
-               log_error("%lu: ooops: invalid key record\n", recnum );
-               break;
-           }
-           if( keyrec.r.key.pubkey_algo == pkc->pubkey_algo
-               && !memcmp(keyrec.r.key.fingerprint, fingerprint, fingerlen) ){
-               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;
-           }
+    for( a = tbl->items[lid & 0x0f]; a; a = a->next )
+       if( a->lid == lid ) {
+           if( flag )
+               *flag = a->flag;
+           return 0;
        }
-    }
-    if( rc != -1 )
-       log_error(_("%s: search_db failed: %s\n"),db_name, g10_errstr(rc) );
-    return rc;
+    return -1;
 }
 
 
+
 /****************
- * If we do not have a local_id in a signature packet, find the owner of
- * the signature packet in our trustdb or insert them into the trustdb
+ * Return the keyid from the primary key identified by LID.
  */
-static int
-set_signature_packets_local_id( PKT_signature *sig )
-{
-    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 = search_record( pkc, &rec );
-       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 */
-    }
-    sig->local_id = pkc->local_id;
-
-  leave:
-    free_public_cert( pkc );
-    return rc;
-}
-
-
-
-static int
-keyid_from_local_id( ulong lid, u32 *keyid )
+int
+keyid_from_lid( ulong lid, u32 *keyid )
 {
     TRUSTREC rec;
     int rc;
 
-    rc = read_record( lid, &rec, RECTYPE_DIR );
+    rc = tdbio_read_record( lid, &rec, 0 );
     if( rc ) {
-       log_error(_("error reading record with local_id %lu: %s\n"),
+       log_error(_("error reading dir record for LID %lu: %s\n"),
                                                    lid, g10_errstr(rc));
        return G10ERR_TRUSTDB;
     }
+    if( rec.rectype == RECTYPE_SDIR )
+       return 0;
     if( rec.rectype != RECTYPE_DIR ) {
-       log_error(_("record with local_id %lu is not a dir record\n"), lid);
+       log_error(_("lid %lu: expected dir record, got type %d\n"),
+                                                   lid, rec.rectype );
+       return G10ERR_TRUSTDB;
+    }
+    if( !rec.r.dir.keylist ) {
+       log_error(_("no primary key for LID %lu\n"), lid );
+       return G10ERR_TRUSTDB;
+    }
+    rc = tdbio_read_record( rec.r.dir.keylist, &rec, RECTYPE_KEY );
+    if( rc ) {
+       log_error(_("error reading primary key for LID %lu: %s\n"),
+                                                   lid, g10_errstr(rc));
        return G10ERR_TRUSTDB;
     }
-    keyid[0] = rec.r.dir.keyid[0];
-    keyid[1] = rec.r.dir.keyid[1];
+    keyid_from_fingerprint( rec.r.key.fingerprint, rec.r.key.fingerprint_len,
+                           keyid );
+
     return 0;
 }
 
+
+ulong
+lid_from_keyblock( KBNODE keyblock )
+{
+    KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+    PKT_public_key *pk;
+    if( !node )
+       BUG();
+    pk = node->pkt->pkt.public_key;
+    if( !pk->local_id ) {
+       TRUSTREC rec;
+
+       get_dir_record( pk, &rec );
+    }
+    return pk->local_id;
+}
+
+
+\f
 /****************
  * Walk through the signatures of a public key.
  * The caller must provide a context structure, with all fields set
@@ -745,9 +381,8 @@ keyid_from_local_id( ulong lid, u32 *keyid )
  * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
  */
 static int
-walk_sigrecs( SIGREC_CONTEXT *c, int create )
+walk_sigrecs( SIGREC_CONTEXT *c )
 {
-    int rc=0;
     TRUSTREC *r;
     ulong rnum;
 
@@ -756,155 +391,219 @@ walk_sigrecs( SIGREC_CONTEXT *c, int create )
     r = &c->ctl.rec;
     if( !c->ctl.init_done ) {
        c->ctl.init_done = 1;
-       if( !c->sigrec ) {
-           rc = read_record( c->local_id, r, RECTYPE_DIR );
-           if( rc ) {
-               log_error(_("%lu: error reading dir record: %s\n"),
-                                       c->local_id, g10_errstr(rc));
-               return rc;
-           }
-           c->sigrec = r->r.dir.sigrec;
-           if( !c->sigrec && create && !r->r.dir.no_sigs ) {
-               rc = build_sigrecs( c->local_id );
-               if( rc ) {
-                   if( rc == G10ERR_BAD_CERT )
-                       rc = -1;  /* maybe no selcficnature */
-                   if( rc != -1 )
-                       log_info(_("%lu: error building sigs on the fly: %s\n"),
-                              c->local_id, g10_errstr(rc) );
-                   c->ctl.eof = 1;
-                   return rc;
-               }
-               rc = read_record( c->local_id, r, RECTYPE_DIR );
-               if( rc ) {
-                   log_error(_("%lu: error re-reading dir record: %s\n"),
-                                           c->local_id, g10_errstr(rc));
-                   return rc;
-               }
-               c->sigrec = r->r.dir.sigrec;
-           }
-           if( !c->sigrec ) {
-               c->ctl.eof = 1;
-               return -1;
-           }
+       read_record( c->lid, r, 0 );
+       if( r->rectype != RECTYPE_DIR ) {
+           c->ctl.eof = 1;
+           return -1;  /* return eof */
        }
+       c->ctl.nextuid = r->r.dir.uidlist;
        /* force a read */
        c->ctl.index = SIGS_PER_RECORD;
-       r->r.sig.chain = c->sigrec;
+       r->r.sig.next = 0;
     }
 
-    /* enter loop to skip deleted sigs */
+    /* need a loop to skip over deleted sigs */
     do {
-       if( c->ctl.index >= SIGS_PER_RECORD ) {
-           /* read the record */
-           rnum = r->r.sig.chain;
+       if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
+           rnum = r->r.sig.next;
+           if( !rnum && c->ctl.nextuid ) { /* read next uid record */
+               read_record( c->ctl.nextuid, r, RECTYPE_UID );
+               c->ctl.nextuid = r->r.uid.next;
+               rnum = r->r.uid.siglist;
+           }
            if( !rnum ) {
                c->ctl.eof = 1;
                return -1;  /* return eof */
            }
-           rc = read_record( rnum, r, RECTYPE_SIG );
-           if( rc ) {
-               log_error(_("error reading sigrec: %s\n"), g10_errstr(rc));
-               c->ctl.eof = 1;
-               return rc;
-           }
-           if( r->r.sig.owner != c->local_id ) {
+           read_record( rnum, r, RECTYPE_SIG );
+           if( r->r.sig.lid != c->lid ) {
                log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
                c->ctl.eof = 1;
-               return G10ERR_TRUSTDB;
+               die_invalid_db();
            }
            c->ctl.index = 0;
        }
-    } while( !r->r.sig.sig[c->ctl.index++].local_id );
-    c->sig_id = r->r.sig.sig[c->ctl.index-1].local_id;
+    } while( !r->r.sig.sig[c->ctl.index++].lid );
+
+    c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
     c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
     return 0;
 }
 
 
 
-
+\f
 /***********************************************
  ************* Trust  stuff  ******************
  ***********************************************/
 
+static int
+trust_letter( unsigned value )
+{
+    switch( value ) {
+      case TRUST_UNKNOWN:   return '-';
+      case TRUST_EXPIRED:   return 'e';
+      case TRUST_UNDEFINED: return 'q';
+      case TRUST_NEVER:     return 'n';
+      case TRUST_MARGINAL:  return 'm';
+      case TRUST_FULLY:     return 'f';
+      case TRUST_ULTIMATE:  return 'u';
+      default:             return  0 ;
+    }
+}
+
+
+void
+register_trusted_key( const char *string )
+{
+    u32 keyid[2];
+    struct keyid_list *r;
+
+    if( classify_user_id( string, keyid, NULL, NULL, NULL ) != 11 ) {
+       log_error(_("'%s' is not a valid long keyID\n"), string );
+       return;
+    }
+
+    for( r = trusted_key_list; r; r = r->next )
+       if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] )
+           return;
+    r = m_alloc( sizeof *r );
+    r->keyid[0] = keyid[0];
+    r->keyid[1] = keyid[1];
+    r->next = trusted_key_list;
+    trusted_key_list = r;
+}
 
 /****************
- * Verify that all our public keys are in the trustDB.
+ * Verify that all our public keys are in the trustdb.
  */
 static int
-verify_own_certs()
+verify_own_keys()
 {
     int rc;
     void *enum_context = NULL;
-    PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
-    PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+    PKT_secret_key *sk = m_alloc_clear( sizeof *sk );
+    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
     u32 keyid[2];
+    struct keyid_list *kl;
+
+    /* put the trusted keys into the trusted key table */
+    for( kl = trusted_key_list; kl; kl = kl->next ) {
+       keyid[0] = kl->keyid[0];
+       keyid[1] = kl->keyid[1];
+       /* get the public key */
+       memset( pk, 0, sizeof *pk );
+       rc = get_pubkey( pk, keyid );
+       if( rc ) {
+           log_info(_("key %08lX: no public key for trusted key - skipped\n"),
+                                                           (ulong)keyid[1] );
+       }
+       else {
+           /* make sure that the pubkey is in the trustdb */
+           rc = query_trust_record( pk );
+           if( rc == -1 ) { /* put it into the trustdb */
+               rc = insert_trust_record( pk );
+               if( rc ) {
+                   log_error(_("key %08lX: can't put it into the trustdb\n"),
+                                                       (ulong)keyid[1] );
+               }
+           }
+           else if( rc ) {
+               log_error(_("key %08lX: query record failed\n"),
+                                                       (ulong)keyid[1] );
+           }
+           else {
+               if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
+                   log_error(_("key %08lX: already in trusted key table\n"),
+                                                         (ulong)keyid[1]);
+               else if( opt.verbose > 1 )
+                   log_info(_("key %08lX: accepted as trusted key.\n"),
+                                                         (ulong)keyid[1]);
+           }
+       }
+       release_public_key_parts( pk );
+    }
 
-    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 is boring for the user.
-        *        Solution:  Sign the secring and the trustring
-        *                   and verify this signature during
-        *                   startup
-        */
+    while( !(rc=enum_secret_keys( &enum_context, sk, 0 ) ) ) {
+       int have_pk = 0;
 
-       keyid_from_skc( skc, keyid );
+       keyid_from_sk( sk, keyid );
 
        if( DBG_TRUST )
-           log_debug("checking secret key %08lX\n", (ulong)keyid[1] );
+           log_debug("key %08lX: checking secret key\n", (ulong)keyid[1] );
+
+       if( is_secret_key_protected( sk ) < 1 )
+           log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
+                                                           (ulong)keyid[1] );
+
+       for( kl = trusted_key_list; kl; kl = kl->next ) {
+           if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
+               goto skip; /* already in trusted key table */
+       }
 
        /* see whether we can access the public key of this secret key */
-       memset( pkc, 0, sizeof *pkc );
-       rc = get_pubkey( pkc, keyid );
+       memset( pk, 0, sizeof *pk );
+       rc = get_pubkey( pk, keyid );
        if( rc ) {
-           log_error(_("keyid %08lX: secret key without public key\n"),
+           log_info(_("key %08lX: secret key without public key - skipped\n"),
                                                            (ulong)keyid[1] );
-           goto leave;
+           goto skip;
        }
-       if( cmp_public_secret_cert( pkc, skc ) ) {
-           log_error(_("keyid %08lX: secret and public key don't match\n"),
+       have_pk=1;
+
+       if( cmp_public_secret_key( pk, sk ) ) {
+           log_info(_("key %08lX: secret and public key don't match\n"),
                                                            (ulong)keyid[1] );
-           rc = G10ERR_GENERAL;
-           goto leave;
+           goto skip;
        }
 
        /* make sure that the pubkey is in the trustdb */
-       rc = query_trust_record( pkc );
+       rc = query_trust_record( pk );
        if( rc == -1 ) { /* put it into the trustdb */
-           rc = insert_trust_record( pkc );
+           rc = insert_trust_record( pk );
            if( rc ) {
-               log_error(_("keyid %08lX: can't put it into the trustdb\n"),
+               log_error(_("key %08lX: can't put it into the trustdb\n"),
                                                            (ulong)keyid[1] );
-               goto leave;
+               goto skip;
            }
        }
        else if( rc ) {
-           log_error(_("keyid %08lX: query record failed\n"), (ulong)keyid[1] );
-           goto leave;
+           log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
+           goto skip;
 
        }
 
        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"),
+           log_debug("key %08lX.%lu: stored into ultikey_table\n",
+                                   (ulong)keyid[1], pk->local_id );
+       if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
+           log_error(_("key %08lX: already in trusted key table\n"),
                                                        (ulong)keyid[1]);
-
-
-       release_secret_cert_parts( skc );
-       release_public_cert_parts( pkc );
+       else if( opt.verbose > 1 )
+           log_info(_("key %08lX: accepted as trusted key.\n"),
+                                                       (ulong)keyid[1]);
+      skip:
+       release_secret_key_parts( sk );
+       if( have_pk )
+           release_public_key_parts( pk );
     }
     if( rc != -1 )
-       log_error(_("enum_secret_keys failed: %s\n"), g10_errstr(rc) );
+       log_error(_("enumerate secret keys failed: %s\n"), g10_errstr(rc) );
     else
        rc = 0;
 
-  leave:
-    free_secret_cert( skc );
-    free_public_cert( pkc );
+    /* release the trusted keyid table */
+    {  struct keyid_list *kl2;
+       for( kl = trusted_key_list; kl; kl = kl2 ) {
+           kl2 = kl->next;
+           m_free( kl );
+       }
+       trusted_key_list = NULL;
+    }
+
+    enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
+    free_secret_key( sk );
+    free_public_key( pk );
     return rc;
 }
 
@@ -927,46 +626,95 @@ print_user_id( const char *text, u32 *keyid )
     m_free(p);
 }
 
-/* (a non-recursive algorithm would be easier) */
+#if 0
 static int
-do_list_sigs( ulong root, ulong pubkey, int depth,
-             LOCAL_ID_INFO *lids, unsigned *lineno )
+print_keyid( FILE *fp, ulong lid )
 {
-    SIGREC_CONTEXT sx;
-    int rc;
-    u32 keyid[2];
+    u32 ki[2];
+    if( keyid_from_lid( lid, ki ) )
+       return fprintf(fp, "????????.%lu", lid );
+    else
+       return fprintf(fp, "%08lX.%lu", (ulong)ki[1], lid );
+}
 
-    memset( &sx, 0, sizeof sx );
-    sx.local_id = pubkey;
-    for(;;) {
-       rc = walk_sigrecs( &sx, 0 );
-       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 whether we already checked this pubkey */
-           if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
-               print_user_id("[ultimately trusted]", keyid);
-               ++*lineno;
+static int
+print_trust( FILE *fp, unsigned trust )
+{
+    int c;
+    switch( trust ) {
+      case TRUST_UNKNOWN:   c = 'o'; break;
+      case TRUST_EXPIRED:   c = 'e'; break;
+      case TRUST_UNDEFINED: c = 'q'; break;
+      case TRUST_NEVER:     c = 'n'; break;
+      case TRUST_MARGINAL:  c = 'm'; break;
+      case TRUST_FULLY:     c = 'f'; break;
+      case TRUST_ULTIMATE:  c = 'u'; break;
+      default: fprintf(fp, "%02x", trust ); return 2;
+    }
+    putc(c, fp);
+    return 1;
+}
+#endif
+
+static int
+print_sigflags( FILE *fp, unsigned flags )
+{
+    if( flags & SIGF_CHECKED ) {
+       fprintf(fp,"%c%c%c",
+          (flags & SIGF_VALID)   ? 'V':'-',
+          (flags & SIGF_EXPIRED) ? 'E':'-',
+          (flags & SIGF_REVOKED) ? 'R':'-');
+    }
+    else if( flags & SIGF_NOPUBKEY)
+       fputs("?--", fp);
+    else
+       fputs("---", fp);
+    return 3;
+}
+
+/* (a non-recursive algorithm would be easier) */
+static int
+do_list_sigs( ulong root, ulong pk_lid, int depth,
+             LOCAL_ID_TABLE lids, unsigned *lineno )
+{
+    SIGREC_CONTEXT sx;
+    int rc;
+    u32 keyid[2];
+
+    memset( &sx, 0, sizeof sx );
+    sx.lid = pk_lid;
+    for(;;) {
+       rc = walk_sigrecs( &sx ); /* should we replace it and use */
+       if( rc )                  /* use a loop like in collect_paths ??*/
+           break;
+       rc = keyid_from_lid( sx.sig_lid, keyid );
+       if( rc ) {
+           printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
+           print_sigflags( stdout, sx.sig_flag );
+           putchar('\n');
+           ++*lineno;
+       }
+       else {
+           printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
+                             (ulong)keyid[1], sx.sig_lid );
+           print_sigflags( stdout, sx.sig_flag );
+           putchar(' ');
+           /* check whether we already checked this pk_lid */
+           if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
+               print_user_id("[ultimately trusted]", keyid);
+               ++*lineno;
            }
-           else if( sx.sig_id == pubkey ) {
+           else if( sx.sig_lid == pk_lid ) {
                printf("[self-signature]\n");
                ++*lineno;
            }
-           else if( sx.sig_id == root ) {
+           else if( sx.sig_lid == root ) {
                printf("[closed]\n");
                ++*lineno;
            }
-           else if( ins_lid_table_item( lids, sx.sig_id, *lineno ) ) {
+           else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
                unsigned refline;
-               qry_lid_table_flag( lids, sx.sig_id, &refline );
+               qry_lid_table_flag( lids, sx.sig_lid, &refline );
                printf("[see line %u]\n", refline);
                ++*lineno;
            }
@@ -977,7 +725,7 @@ do_list_sigs( ulong root, ulong pubkey, int depth,
            else {
                print_user_id( "", keyid );
                ++*lineno;
-               rc = do_list_sigs( root, sx.sig_id, depth+1, lids, lineno );
+               rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
                if( rc )
                    break;
            }
@@ -994,15 +742,13 @@ list_sigs( ulong pubkey_id )
 {
     int rc;
     u32 keyid[2];
-    LOCAL_ID_INFO *lids;
+    LOCAL_ID_TABLE 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);
+    rc = keyid_from_lid( pubkey_id, keyid );
+    if( rc )
        return rc;
-    }
-    printf("Signatures of %08lX(%lu) ", (ulong)keyid[1], pubkey_id );
+    printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
     print_user_id("", keyid);
     printf("----------------------\n");
 
@@ -1013,483 +759,287 @@ list_sigs( ulong pubkey_id )
     return rc;
 }
 
-
-
 /****************
- * Function to collect all trustpaths
+ * List all records of a public key
  */
 static int
-do_list_path( TRUST_INFO *stack, int depth, int max_depth,
-             LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist )
+list_records( ulong lid )
 {
-    SIGREC_CONTEXT sx;
-    unsigned last_depth;
     int rc;
+    TRUSTREC dr, ur, rec;
+    ulong recno;
 
-    assert(depth);
+    rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
+    if( rc ) {
+       log_error(_("lid %lu: read dir record failed: %s\n"),
+                                               lid, g10_errstr(rc));
+       return rc;
+    }
+    tdbio_dump_record( &dr, stdout );
 
-    /*printf("%2lu/%d: scrutinizig\n", stack[depth-1], depth);*/
-    if( depth >= max_depth || depth >= MAX_LIST_SIGS_DEPTH-1 ) {
-       /*printf("%2lu/%d: too deeply nested\n", stack[depth-1], depth);*/
-       return 0;
+    for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
+       rc = tdbio_read_record( recno, &rec, 0 );
+       if( rc ) {
+           log_error(_("lid %lu: read key record failed: %s\n"),
+                                               lid, g10_errstr(rc));
+           return rc;
+       }
+       tdbio_dump_record( &rec, stdout );
     }
-    memset( &sx, 0, sizeof sx );
-    sx.local_id = stack[depth-1].lid;
-    /* loop over all signatures. If we do not have any, try to
-     * create them */
-    while( !(rc = walk_sigrecs( &sx, 1 )) ) {
-       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;
+    for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
+       rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
+       if( rc ) {
+           log_error(_("lid %lu: read uid record failed: %s\n"),
+                                               lid, g10_errstr(rc));
+           return rc;
+       }
+       tdbio_dump_record( &ur, stdout );
+       /* preference records */
+       for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
+           rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
+           if( rc ) {
+               log_error(_("lid %lu: read pref record failed: %s\n"),
+                                                   lid, g10_errstr(rc));
+               return rc;
            }
-           /*putchar('.'); fflush(stdout);*/
-           /*printf("%2lu/%d: found\n", sx.sig_id, depth);*/
+           tdbio_dump_record( &rec, stdout );
        }
-       else {
-           rc = do_list_path( stack, depth+1, max_depth, lids, tslist);
-           if( rc && rc != -1 )
-               break;
+       /* sig records */
+       for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
+           rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
+           if( rc ) {
+               log_error(_("lid %lu: read sig record failed: %s\n"),
+                                                   lid, g10_errstr(rc));
+               return rc;
+           }
+           tdbio_dump_record( &rec, stdout );
        }
     }
-    return rc==-1? 0 : rc;
+
+    /* add cache record dump here */
+
+
+
+    return rc;
 }
 
 
 
+
 /****************
- * Check all the sigs of the given keyblock and mark them
- * as checked. Valid signatures which are duplicates are
- * also marked [shall we check them at all?]
- * FIXME: what shall we do if we have duplicate signatures where only
- *       some of them are bad?
+ * stack is an array of (max_path+1) elements. If trust_seg_head is not
+ * NULL it is a pointer to a variable which will receive a linked list
+ * of trust paths - The caller has to free the memory.
  */
 static int
-check_sigs( KBNODE keyblock, int *selfsig_okay, int *revoked )
+collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
+              TRUST_INFO *stack, TRUST_SEG_LIST *trust_seg_head )
 {
-    KBNODE node;
-    int rc;
-    LOCAL_ID_INFO *dups = NULL;
+    ulong rn, uidrn;
+    int marginal=0;
+    int fully=0;
+    LOCAL_ID_TABLE sigs_seen = NULL;
+
+    if( depth >= max_depth )  /* max cert_depth reached */
+       return TRUST_UNDEFINED;
+
+    stack[depth].lid = drec->r.dir.lid;
+    stack[depth].otrust = drec->r.dir.ownertrust;
+    stack[depth].trust = 0;
+    {  int i;
+
+       for(i=0; i < depth; i++ )
+           if( stack[i].lid == drec->r.dir.lid )
+               return TRUST_UNDEFINED; /* closed (we already visited this lid) */
+    }
+    if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) {
+       /* we are at the end of a path */
+       TRUST_SEG_LIST tsl;
+       int i;
 
-    *selfsig_okay = 0;
-    *revoked = 0;
-    for( node=keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_SIGNATURE
-           && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10
-                 || node->pkt->pkt.signature->sig_class == 0x20
-                 || node->pkt->pkt.signature->sig_class == 0x30) ) {
-           int selfsig;
-           rc = check_key_signature( keyblock, node, &selfsig );
-           if( !rc ) {
-               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( selfsig ) {
-                   node->flag |= 2; /* mark signature valid */
-                   *selfsig_okay = 1;
-               }
-               else if( node->pkt->pkt.signature->sig_class == 0x20 )
-                   *revoked = 1;
-               else
-                   node->flag |= 1; /* mark signature valid */
-
-               if( node->pkt->pkt.signature->sig_class != 0x20 ) {
-                   if( !dups )
-                       dups = new_lid_table();
-                   if( ins_lid_table_item( dups,
-                                       node->pkt->pkt.signature->local_id, 0) )
-                       node->flag |= 4; /* mark as duplicate */
-               }
-           }
-           if( DBG_TRUST )
-               log_debug("trustdb: sig from %08lX(%lu): %s%s\n",
-                               (ulong)node->pkt->pkt.signature->keyid[1],
-                               node->pkt->pkt.signature->local_id,
-                               g10_errstr(rc), (node->flag&4)?"  (dup)":"" );
+       stack[depth].trust = TRUST_ULTIMATE;
+       stack[depth].otrust = TRUST_ULTIMATE;
+       if( trust_seg_head ) {
+           /* we can now put copy our current stack to the trust_seg_list */
+           tsl = m_alloc( sizeof *tsl + (depth+1)*sizeof( TRUST_INFO ) );
+           for(i=0; i <= depth; i++ )
+               tsl->path[i] = stack[i];
+           tsl->pathlen = i;
+           tsl->next = *trust_seg_head;
+           *trust_seg_head = tsl;
        }
-    }
-    if( dups )
-       release_lid_table(dups);
-    return 0;
-}
+       return TRUST_ULTIMATE;
+    }
+
+    /* loop over all user-ids */
+    if( !all )
+       sigs_seen = new_lid_table();
+    for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) {
+       TRUSTREC rec;  /* used for uids and sigs */
+       ulong sigrn;
+
+       read_record( rn, &rec, RECTYPE_UID );
+       uidrn = rec.r.uid.next;
+       if( !(rec.r.uid.uidflags & UIDF_CHECKED) )
+           continue; /* user id has not been checked */
+       if( !(rec.r.uid.uidflags & UIDF_VALID) )
+           continue; /* user id is not valid */
+       if( (rec.r.uid.uidflags & UIDF_REVOKED) )
+           continue; /* user id has been revoked */
+
+       /* loop over all signature records */
+       for( rn = rec.r.uid.siglist; rn; rn = sigrn ) {
+           int i;
 
+           read_record( rn, &rec, RECTYPE_SIG );
+           sigrn = rec.r.sig.next;
 
-/****************
- * If we do not have sigrecs for the given key, build them and write them
- * to the trustdb
- */
-static int
-build_sigrecs( ulong pubkeyid )
-{
-    TRUSTREC rec, krec, rec2;
-    KBNODE keyblock = NULL;
-    KBNODE node;
-    int rc=0;
-    int i, selfsig, revoked;
-    ulong rnum, rnum2;
-    ulong first_sigrec = 0;
+           for(i=0; i < SIGS_PER_RECORD; i++ ) {
+               TRUSTREC tmp;
+               int ot, nt;
+               int unchecked = 0;
 
-    if( DBG_TRUST )
-       log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid );
+               if( !rec.r.sig.sig[i].lid )
+                   continue; /* skip deleted sigs */
+               if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) ) {
+                   if( !all )
+                       continue; /* skip unchecked signatures */
+                   unchecked = 1;
+               }
+               else {
+                   if( !(rec.r.sig.sig[i].flag & SIGF_VALID) )
+                       continue; /* skip invalid signatures */
+                   if( (rec.r.sig.sig[i].flag & SIGF_EXPIRED) )
+                       continue; /* skip expired signatures */
+                   if( (rec.r.sig.sig[i].flag & SIGF_REVOKED) )
+                       continue; /* skip revoked signatures */
+               }
 
-    /* get the keyblock */
-    if( (rc=read_record( pubkeyid, &rec, RECTYPE_DIR )) ) {
-       log_error(_("%lu: build_sigrecs: can't read dir record\n"), pubkeyid );
-       goto leave;
-    }
-    if( (rc=read_record( rec.r.dir.keyrec, &krec, RECTYPE_KEY )) ) {
-       log_error(_("%lu: build_sigrecs: can't read key record\n"), pubkeyid);
-       goto leave;
-    }
-    rc = get_keyblock_byfprint( &keyblock, krec.r.key.fingerprint,
-                                          krec.r.key.fingerprint_len );
-    if( rc ) {
-       log_error(_("build_sigrecs: get_keyblock_byfprint failed\n") );
-       goto leave;
-    }
-    /* check all key signatures */
-    rc = check_sigs( keyblock, &selfsig, &revoked );
-    if( rc ) {
-       log_error(_("build_sigrecs: check_sigs failed\n") );
-       goto leave;
-    }
-    if( !selfsig ) {
-       log_error(_("build_sigrecs: self-certificate missing\n") );
-       update_no_sigs( pubkeyid, 2 );
-       rc = G10ERR_BAD_CERT;
-       goto leave;
-    }
-    if( revoked ) {
-       log_info(_("build_sigrecs: key has been revoked\n") );
-       update_no_sigs( pubkeyid, 3 );
-    }
-    else
-       update_no_sigs( pubkeyid, 0 ); /* assume we have sigs */
-
-    /* valid key signatures are now marked; we can now build the
-     * sigrecs */
-    memset( &rec, 0, sizeof rec );
-    rec.rectype = RECTYPE_SIG;
-    i = 0;
-    rnum = rnum2 = 0;
-    for( node=keyblock; node; node = node->next ) {
-       /* insert sigs which are not a selfsig nor a duplicate */
-       if( (node->flag & 1) && !(node->flag & 4) ) {
-           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 errors of the trustdb or a
-                * remove operation on the pubkey database - which should
-                * not disturb us, because we have to chance them anyway. */
-               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.sig.owner = pubkeyid;
-                   rec2.r.sig.chain = rnum; /* the next record number */
-                   rc = write_record( rnum2, &rec2 );
-                   if( rc ) {
-                       log_error(_("build_sigrecs: write_record failed\n") );
-                       goto leave;
+               /* visit every signer only once (a signer may have
+                * signed more than one user ID) */
+               if( sigs_seen && ins_lid_table_item( sigs_seen,
+                                                    rec.r.sig.sig[i].lid, 0) )
+                   continue; /* we already have this one */
+
+               read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
+               if( tmp.rectype != RECTYPE_DIR ) {
+                   if( tmp.rectype != RECTYPE_SDIR )
+                       log_info("oops: lid %lu: sig %lu has rectype %d"
+                            " - skipped\n",
+                           drec->r.dir.lid, tmp.recnum, tmp.rectype );
+                   continue;
+               }
+               ot = tmp.r.dir.ownertrust & TRUST_MASK;
+               if( ot >= TRUST_FULLY )
+                   ot = TRUST_FULLY;  /* just in case */
+               nt = collect_paths( depth+1, max_depth, all, &tmp, stack,
+                                                       trust_seg_head );
+               nt &= TRUST_MASK;
+
+               if( nt < TRUST_MARGINAL || unchecked ) {
+                   continue;
+               }
+
+               if( nt == TRUST_ULTIMATE ) {
+                   /* we have signed this key and only in this special case
+                    * we assume that this one is fully trusted */
+                   if( !all ) {
+                       if( sigs_seen )
+                           release_lid_table( sigs_seen );
+                       return (stack[depth].trust = TRUST_FULLY);
                    }
-                   if( !first_sigrec )
-                       first_sigrec = rnum2;
                }
-               rec2 = rec;
-               rnum2 = rnum;
-               memset( &rec, 0, sizeof rec );
-               rec.rectype = RECTYPE_SIG;
-               i = 0;
-           }
-           rec.r.sig.sig[i].local_id = node->pkt->pkt.signature->local_id;
-           rec.r.sig.sig[i].flag = 0;
-           i++;
-       }
-    }
-    if( i || rnum2 ) {
-       /* write the record */
-       rnum = new_recnum();
-       if( rnum2 ) { /* write the stored record */
-           rec2.r.sig.owner = pubkeyid;
-           rec2.r.sig.chain = rnum;
-           rc = write_record( rnum2, &rec2 );
-           if( rc ) {
-               log_error(_("build_sigrecs: write_record failed\n") );
-               goto leave;
-           }
-           if( !first_sigrec )
-               first_sigrec = rnum2;
-       }
-       if( i ) { /* write the pending record */
-           rec.r.sig.owner = pubkeyid;
-           rec.r.sig.chain = 0;
-           rc = write_record( rnum, &rec );
-           if( rc ) {
-               log_error(_("build_sigrecs: write_record failed\n") );
-               goto leave;
-           }
-           if( !first_sigrec )
-               first_sigrec = rnum;
-       }
-    }
-    if( first_sigrec ) {
-       /* update the dir record */
-       if( (rc =read_record( pubkeyid, &rec, RECTYPE_DIR )) ) {
-           log_error(_("update_dir_record: read failed\n"));
-           goto leave;
-       }
-       rec.r.dir.sigrec = first_sigrec;
-       if( (rc=write_record( pubkeyid, &rec )) ) {
-           log_error(_("update_dir_record: write failed\n"));
-           goto leave;
-       }
-    }
-    else
-       update_no_sigs( pubkeyid, revoked? 3:1 ); /* no signatures */
 
-  leave:
-    release_kbnode( keyblock );
-    if( DBG_TRUST )
-       log_debug(_("trustdb: build_sigrecs: %s\n"), g10_errstr(rc) );
-    return rc;
-}
+               if( nt > ot )
+                   nt = ot;
 
-/****************
- * Make a list of trust paths
- */
-static int
-make_tsl( ulong pubkey_id, TRUST_SEG_LIST *ret_tslist )
-{
-    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;
-    }
-    else {
-       stack[0].lid = pubkey_id;
-       stack[0].trust = 0;
-       rc = do_list_path( stack, 1, max_depth, lids, &tslist );
-    }
-    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;
+               if( nt >= TRUST_FULLY )
+                   fully++;
+               if( nt >= TRUST_MARGINAL )
+                   marginal++;
+
+               if( fully >= opt.completes_needed
+                   || marginal >= opt.marginals_needed ) {
+                   if( !all ) {
+                       if( sigs_seen )
+                           release_lid_table( sigs_seen );
+                       return (stack[depth].trust = TRUST_FULLY);
+                   }
                }
            }
        }
-       release_lid_table(work);
-       *ret_tslist = tslist;
     }
-    else
-       ; /* FIXME: release tslist */
-    release_lid_table(lids);
-    return rc;
+    if( sigs_seen )
+       release_lid_table( sigs_seen );
+    if( all && ( fully >= opt.completes_needed
+                || marginal >= opt.marginals_needed ) ) {
+       return (stack[depth].trust = TRUST_FULLY );
+    }
+    if( marginal ) {
+       return (stack[depth].trust = TRUST_MARGINAL);
+    }
+    return (stack[depth].trust=TRUST_UNDEFINED);
 }
 
 
 /****************
- * 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 thinking here. e.g. we should never increase
- *       the trust value.
- *
- * Do not do it for duplicates.
+ * Given the directory record of a key, check whether we can
+ * find a path to an ultimately trusted key.  We do this by
+ * checking all key signatures up to a some depth.
  */
 static int
-propagate_trust( TRUST_SEG_LIST tslist )
+verify_key( int max_depth, TRUSTREC *drec )
 {
-    int i, rc;
-    unsigned trust, tr;
-    TRUST_SEG_LIST tsl;
+    TRUST_INFO *tmppath = m_alloc_clear( (max_depth+1)* sizeof *tmppath );
+    int tr;
 
-    for(tsl = tslist; tsl; tsl = tsl->next ) {
-       if( tsl->dup )
-           continue;
-       assert( tsl->nseg );
-       /* the last segment is always an 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, &tr );
-               if( rc )
-                   return rc;
-               if( tr < trust )
-                   trust = tr;
-           }
-       }
-    }
-    return 0;
+    tr = collect_paths( 0, max_depth, 0, drec, tmppath, NULL );
+    m_free( tmppath );
+    return tr;
 }
 
 
+
+
 /****************
- * we have the pubkey record but nothing more is known.
- * (function may re-read dr)
+ * we have the pubkey record and all needed informations are in the trustdb
+ * but nothing more is known.
  */
 static int
-do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel )
+do_check( TRUSTREC *dr, unsigned *validity )
 {
-    int i, rc=0;
-    TRUST_SEG_LIST tsl, tsl2, tslist;
-    int marginal, fully;
-    int fully_needed = opt.completes_needed;
-    int marginal_needed = opt.marginals_needed;
-    unsigned tflags = 0;
-
-    assert( fully_needed > 0 && marginal_needed > 1 );
-
-
-    *trustlevel = TRUST_UNDEFINED;
-
-    /* verify the cache */
-
-    /* do we have sigrecs */
-    if( !dr->r.dir.sigrec && !dr->r.dir.no_sigs) {
-       /* no sigrecs, so build them */
-       rc = build_sigrecs( pubkeyid );
-       if( !rc ) /* and read again */
-           rc = read_record( pubkeyid, dr, RECTYPE_DIR );
+    if( !dr->r.dir.keylist ) {
+       log_error(_("Ooops, no keys\n"));
+       return G10ERR_TRUSTDB;
     }
-
-    if( dr->r.dir.no_sigs == 3 )
-       tflags |= TRUST_FLAG_REVOKED;
-
-    if( !rc && !dr->r.dir.sigrec ) {
-       /* See whether this is our own key */
-       if( !qry_lid_table_flag( ultikey_table, pubkeyid, NULL ) )
-           *trustlevel = tflags | TRUST_ULTIMATE;
-       return 0;
+    if( !dr->r.dir.uidlist ) {
+       log_error(_("Ooops, no user ids\n"));
+       return G10ERR_TRUSTDB;
     }
-    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;
-
-       if( opt.verbose ) {
-           log_info("tslist segs:" );
-           for(i=0; i < tsl->nseg; i++ )
-               fprintf(stderr, "  %lu/%02x", tsl->seg[i].lid,
-                                               tsl->seg[i].trust );
-           putc('\n',stderr);
+    if( tdbio_db_matches_options()
+       && (dr->r.dir.dirflags & DIRF_VALVALID)
+       && dr->r.dir.validity )
+       *validity = dr->r.dir.validity;
+    else {
+       *validity = verify_key( opt.max_cert_depth, dr );
+       if( (*validity & TRUST_MASK) >= TRUST_UNDEFINED
+           && tdbio_db_matches_options() ) {
+           /* update the cached validity value */
+           dr->r.dir.validity = (*validity & TRUST_MASK);
+           dr->r.dir.dirflags |= DIRF_VALVALID;
+           write_record( dr );
        }
     }
 
-    /* and see whether 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 = tflags | TRUST_ULTIMATE; /* our own key */
-           break;
-       }
-       if( tsl->seg[0].trust == TRUST_FULLY ) {
-           marginal++;
-           fully++;
-       }
-       else if( tsl->seg[0].trust == TRUST_MARGINAL )
-           marginal++;
-
-       if( fully >= fully_needed ) {
-           *trustlevel = tflags | TRUST_FULLY;
-           break;
-       }
-    }
-    if( !tsl && marginal >= marginal_needed )
-       *trustlevel = tflags | TRUST_MARGINAL;
+    if( dr->r.dir.dirflags & DIRF_REVOKED )
+       *validity |= TRUST_FLAG_REVOKED;
 
-    /* cache the tslist */
-    if( last_trust_web_key ) {
-       for( tsl = last_trust_web_tslist; tsl; tsl = tsl2 ) {
-           tsl2 = tsl->next;
-           m_free(tsl);
-       }
-    }
-    last_trust_web_key = pubkeyid;
-    last_trust_web_tslist = tslist;
     return 0;
 }
 
-
-/***********************************************
- ****************  API ************************
- ***********************************************/
-
+\f
 /****************
  * Perform some checks over the trustdb
  *  level 0: only open the db
@@ -1504,54 +1054,19 @@ init_trustdb( int level, const char *dbname )
        ultikey_table = new_lid_table();
 
     if( !level || level==1 ) {
-       char *fname = dbname? m_strdup( dbname )
-                           : make_filename(opt.homedir, "trustdb.gpg", 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 ) {
-               char *p = strrchr( fname, '/' );
-               assert(p);
-               *p = 0;
-               if( access( fname, F_OK ) ) {
-                   if( strlen(fname) >= 7
-                       && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) {
-                     #if __MINGW32__
-                       if( mkdir( fname ) )
-                     #else
-                       if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
-                     #endif
-                           log_fatal(_("can't create directory '%s': %s\n"),
-                                       fname, strerror(errno) );
-                   }
-                   else
-                       log_fatal(_("directory '%s' does not exist!\n"), fname );
-               }
-               *p = '/';
-               create_db( fname );
-           }
-       }
-       m_free(db_name);
-       db_name = fname;
-
+       rc = tdbio_set_dbname( dbname, !!level );
+       if( rc )
+           return rc;
        if( !level )
            return 0;
 
-       /* we can verify a signature about our local data (secring and trustdb)
-        * in ~/.gnupg/ 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();
+       /* verify that our own keys are in the trustDB
+        * or move them to the trustdb. */
+       rc = verify_own_keys();
 
-           /* should we check whether there is no other ultimately trusted
-            * key in the database? */
+       /* should we check whether there is no other ultimately trusted
+        * key in the database? */
 
-       }
     }
     else
        BUG();
@@ -1565,134 +1080,498 @@ list_trustdb( const char *username )
 {
     TRUSTREC rec;
 
-    if( username ) {
-       PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+    if( username && *username == '#' ) {
+       int rc;
+       ulong lid = atoi(username+1);
+
+       if( (rc = list_records( lid)) )
+           log_error(_("user '%s' read problem: %s\n"),
+                                           username, g10_errstr(rc));
+       else if( (rc = list_sigs( lid )) )
+           log_error(_("user '%s' list problem: %s\n"),
+                                           username, g10_errstr(rc));
+    }
+    else if( username ) {
+       PKT_public_key *pk = m_alloc_clear( sizeof *pk );
        int rc;
 
-       if( (rc = get_pubkey_byname( pkc, username )) )
-           log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
-       else if( (rc=search_record( pkc, &rec )) && rc != -1 )
-           log_error("problem finding '%s' in trustdb: %s\n",
+       if( (rc = get_pubkey_byname( NULL, pk, username, NULL )) )
+           log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
+       else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
+           log_error(_("problem finding '%s' in trustdb: %s\n"),
                                                username, g10_errstr(rc));
        else if( rc == -1 )
-           log_error("user '%s' not in trustdb\n", username);
-       else if( (rc = list_sigs( pkc->local_id )) )
-           log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
-       free_public_cert( pkc );
+           log_error(_("user '%s' not in trustdb\n"), username);
+       else if( (rc = list_records( pk->local_id)) )
+           log_error(_("user '%s' read problem: %s\n"),
+                                               username, g10_errstr(rc));
+       else if( (rc = list_sigs( pk->local_id )) )
+           log_error(_("user '%s' list problem: %s\n"),
+                                               username, g10_errstr(rc));
+       free_public_key( pk );
     }
     else {
        ulong recnum;
        int i;
 
-       printf("TrustDB: %s\n", db_name );
-       for(i=9+strlen(db_name); i > 0; i-- )
+       printf("TrustDB: %s\n", tdbio_get_dbname() );
+       for(i=9+strlen(tdbio_get_dbname()); i > 0; i-- )
            putchar('-');
        putchar('\n');
-       for(recnum=0; !read_record( recnum, &rec, 0); recnum++ )
-           dump_record( recnum, &rec, stdout );
+       for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ )
+           tdbio_dump_record( &rec, stdout );
     }
 }
 
+/****************
+ * Print a list of all defined owner trust value.
+ */
 void
-list_trust_path( int max_depth, const char *username )
+export_ownertrust()
 {
-    int rc;
-    int wipe=0;
-    int i;
     TRUSTREC rec;
-    PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+    TRUSTREC rec2;
+    ulong recnum;
+    int i;
+    byte *p;
+    int rc;
 
-    if( max_depth < 0 ) {
-       wipe = 1;
-       max_depth = -max_depth;
+    printf(_("# List of assigned trustvalues, created %s\n"
+            "# (Use \"gpgm --import-ownertrust\" to restore them)\n"),
+          asctimestamp( make_timestamp() ) );
+    for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
+       if( rec.rectype == RECTYPE_DIR ) {
+           if( !rec.r.dir.keylist ) {
+               log_error(_("directory record w/o primary key\n"));
+               continue;
+           }
+           if( !rec.r.dir.ownertrust )
+               continue;
+           rc = tdbio_read_record( rec.r.dir.keylist, &rec2, RECTYPE_KEY);
+           if( rc ) {
+               log_error(_("error reading key record: %s\n"), g10_errstr(rc));
+               continue;
+           }
+           p = rec2.r.key.fingerprint;
+           for(i=0; i < rec2.r.key.fingerprint_len; i++, p++ )
+               printf("%02X", *p );
+           printf(":%u:\n", (unsigned)rec.r.dir.ownertrust );
+       }
     }
+}
 
-    if( (rc = get_pubkey_byname( pkc, username )) )
-       log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
-    else if( (rc=search_record( pkc, &rec )) && rc != -1 )
-       log_error("problem finding '%s' in trustdb: %s\n",
-                                           username, g10_errstr(rc));
-    else if( rc == -1 ) {
-       log_info("user '%s' not in trustdb - inserting\n", username);
-       rc = insert_trust_record( pkc );
-       if( rc )
-           log_error("failed to put '%s' into trustdb: %s\n", username, g10_errstr(rc));
-       else {
-           assert( pkc->local_id );
-       }
+
+void
+import_ownertrust( const char *fname )
+{
+    FILE *fp;
+    int is_stdin=0;
+    char line[256];
+    char *p;
+    size_t n, fprlen;
+    unsigned otrust;
+
+    if( !fname || (*fname == '-' && !fname[1]) ) {
+       fp = stdin;
+       fname = "[stdin]";
+       is_stdin = 1;
+    }
+    else if( !(fp = fopen( fname, "r" )) ) {
+       log_error_f(fname, _("can't open file: %s\n"), strerror(errno) );
+       return;
     }
 
-    if( !rc ) {
-       TRUST_SEG_LIST tsl, tslist = NULL;
+    while( fgets( line, DIM(line)-1, fp ) ) {
+       TRUSTREC rec;
+       int rc;
 
-       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;
+       if( !*line || *line == '#' )
+           continue;
+       n = strlen(line);
+       if( line[n-1] != '\n' ) {
+           log_error_f(fname, _("line too long\n") );
+           /* ... or last line does not have a LF */
+           break; /* can't continue */
        }
-       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;
-                       }
-                   }
+       for(p = line; *p && *p != ':' ; p++ )
+           if( !isxdigit(*p) )
+               break;
+       if( *p != ':' ) {
+           log_error_f(fname, _("error: missing colon\n") );
+           continue;
+       }
+       fprlen = p - line;
+       if( fprlen != 32 && fprlen != 40 ) {
+           log_error_f(fname, _("error: invalid fingerprint\n") );
+           continue;
+       }
+       if( sscanf(p, ":%u:", &otrust ) != 1 ) {
+           log_error_f(fname, _("error: no ownertrust value\n") );
+           continue;
+       }
+       if( !otrust )
+           continue; /* no otrust defined - no need to update or insert */
+       /* convert the ascii fingerprint to binary */
+       for(p=line, fprlen=0; *p != ':'; p += 2 )
+           line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
+       line[fprlen] = 0;
+
+      repeat:
+       rc = tdbio_search_dir_byfpr( line, fprlen, 0, &rec );
+       if( !rc ) { /* found: update */
+           if( rec.r.dir.ownertrust )
+               log_info("LID %lu: changing trust from %u to %u\n",
+                         rec.r.dir.lid, rec.r.dir.ownertrust, otrust );
+           else
+               log_info("LID %lu: setting trust to %u\n",
+                                  rec.r.dir.lid, otrust );
+           rec.r.dir.ownertrust = otrust;
+           write_record( &rec );
+       }
+       else if( rc == -1 ) { /* not found; get the key from the ring */
+           PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+
+           log_info_f(fname, _("key not in trustdb, searching ring.\n"));
+           rc = get_pubkey_byfprint( pk, line, fprlen );
+           if( rc )
+               log_info_f(fname, _("key not in ring: %s\n"), g10_errstr(rc));
+           else {
+               rc = query_trust_record( pk );  /* only as assertion */
+               if( rc != -1 )
+                   log_error_f(fname, _("Oops: key is now in trustdb???\n"));
+               else {
+                   rc = insert_trust_record( pk );
+                   if( !rc )
+                       goto repeat; /* update the ownertrust */
+                   log_error_f(fname, _("insert trust record failed: %s\n"),
+                                                          g10_errstr(rc) );
                }
-               release_lid_table(work);
            }
-           release_lid_table(lids);
        }
+       else /* error */
+           log_error_f(fname, _("error finding dir record: %s\n"),
+                                                   g10_errstr(rc));
+    }
+    if( ferror(fp) )
+       log_error_f(fname, _("read error: %s\n"), strerror(errno) );
+    if( !is_stdin )
+       fclose(fp);
+    do_sync();
+}
+
+
+
+
+static void
+print_path( int pathlen, TRUST_INFO *path, FILE *fp, ulong highlight )
+{
+    int rc, c, i;
+    u32 keyid[2];
+    char *p;
+    size_t n;
+
+    for( i = 0; i < pathlen; i++ )  {
+       if( highlight )
+           fputs(highlight == path[i].lid? "* ":"  ", fp );
+       rc = keyid_from_lid( path[i].lid, keyid );
        if( rc )
-           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;
+           fprintf(fp, "????????.%lu:", path[i].lid );
+       else
+           fprintf(fp,"%08lX.%lu:", (ulong)keyid[1], path[i].lid );
+       c = trust_letter(path[i].otrust);
+       if( c )
+           putc( c, fp );
+       else
+           fprintf( fp, "%02x", path[i].otrust );
+       putc('/', fp);
+       c = trust_letter(path[i].trust);
+       if( c )
+           putc( c, fp );
+       else
+           fprintf( fp, "%02x", path[i].trust );
+       putc(' ', fp);
+       p = get_user_id( keyid, &n );
+       putc(' ', fp);
+       putc('\"', fp);
+       print_string( fp, p, n > 40? 40:n, 0 );
+       putc('\"', fp);
+       m_free(p);
+       putc('\n', fp );
+    }
+}
 
-           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 );
+
+static int
+cmp_tsl_array( const void *xa, const void *xb )
+{
+    TRUST_SEG_LIST a = *(TRUST_SEG_LIST*)xa;
+    TRUST_SEG_LIST b = *(TRUST_SEG_LIST*)xb;
+    return a->pathlen - b->pathlen;
+}
+
+
+static void
+sort_tsl_list( TRUST_SEG_LIST *trust_seg_list )
+{
+    TRUST_SEG_LIST *array, *tail, tsl;
+    size_t n;
+
+    for(n=0, tsl = *trust_seg_list; tsl; tsl = tsl->next )
+       n++;
+    array = m_alloc( (n+1) * sizeof *array );
+    for(n=0, tsl = *trust_seg_list; tsl; tsl = tsl->next )
+       array[n++] = tsl;
+    array[n] = NULL;
+    qsort( array, n, sizeof *array, cmp_tsl_array );
+    *trust_seg_list = NULL;
+    tail = trust_seg_list;
+    for(n=0; (tsl=array[n]); n++ ) {
+       *tail = tsl;
+       tail = &tsl->next;
+    }
+    m_free( array );
+}
+
+
+void
+list_trust_path( const char *username )
+{
+    int rc;
+    TRUSTREC rec;
+    TRUST_INFO *tmppath;
+    TRUST_SEG_LIST trust_seg_list, tsl, tsl2;
+    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+
+    if( (rc = get_pubkey_byname(NULL, pk, username, NULL )) )
+       log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
+    else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
+       log_error(_("problem finding '%s' in trustdb: %s\n"),
+                                           username, g10_errstr(rc));
+    else if( rc == -1 ) {
+       log_info(_("user '%s' not in trustdb - inserting\n"), username);
+       rc = insert_trust_record( pk );
+       if( rc )
+           log_error(_("failed to put '%s' into trustdb: %s\n"),
+                                                   username, g10_errstr(rc));
+       else {
+           assert( pk->local_id );
+       }
+    }
+    free_public_key( pk );
+
+    /* collect the paths */
+    tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
+    trust_seg_list = NULL;
+    collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &trust_seg_list );
+    m_free( tmppath );
+    sort_tsl_list( &trust_seg_list );
+    /* and now print them */
+    for(tsl = trust_seg_list; tsl; tsl = tsl->next ) {
+       print_path( tsl->pathlen, tsl->path, stdout, 0 );
+       if( tsl->next )
            putchar('\n');
+    }
+
+    /* release the list */
+    for(tsl = trust_seg_list; tsl; tsl = tsl2 ) {
+       tsl2 = tsl->next;
+       m_free( tsl );
+    }
+    trust_seg_list = NULL;
+}
+
+
+/****************
+ * Check the complete trustdb or only the entries for the given username.
+ * We check the complete database. If a username is given or the special
+ * username "*" is used, a complete recheck is done.  With no user ID
+ * only the records which are not yet checkd are now checked.
+ */
+void
+check_trustdb( const char *username )
+{
+    TRUSTREC rec;
+    KBNODE keyblock = NULL;
+    KBPOS kbpos;
+    int rc;
+    int recheck = username && *username == '*' && !username[1];
+
+    if( username && !recheck ) {
+       rc = find_keyblock_byname( &kbpos, username );
+       if( !rc )
+           rc = read_keyblock( &kbpos, &keyblock );
+       if( rc ) {
+           log_error(_("%s: keyblock read problem: %s\n"),
+                                   username, g10_errstr(rc));
        }
+       else {
+           int modified;
+
+           rc = update_trust_record( keyblock, 1, &modified );
+           if( rc == -1 ) { /* not yet in trustdb: insert */
+               rc = insert_trust_record(
+                           find_kbnode( keyblock, PKT_PUBLIC_KEY
+                                      ) ->pkt->pkt.public_key );
+
+           }
+           if( rc )
+               log_error(_("%s: update failed: %s\n"),
+                                          username, g10_errstr(rc) );
+           else if( modified )
+               log_info(_("%s: updated\n"), username );
+           else
+               log_info(_("%s: okay\n"), username );
+
+       }
+       release_kbnode( keyblock ); keyblock = NULL;
     }
+    else {
+       ulong recnum;
+       ulong count=0, upd_count=0, err_count=0, skip_count=0;
+
+       for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
+           if( rec.rectype == RECTYPE_DIR ) {
+               TRUSTREC tmp;
+               int modified;
+
+               if( !rec.r.dir.keylist ) {
+                   log_info(_("lid %lu: dir record w/o key - skipped\n"),
+                                                                 recnum);
+                   count++;
+                   skip_count++;
+                   continue;
+               }
+
+               read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY );
+
+               rc = get_keyblock_byfprint( &keyblock,
+                                           tmp.r.key.fingerprint,
+                                           tmp.r.key.fingerprint_len );
+               if( rc ) {
+                   log_error(_("lid %lu: keyblock not found: %s\n"),
+                                                recnum, g10_errstr(rc) );
+                   count++;
+                   skip_count++;
+                   continue;
+               }
+
+               rc = update_trust_record( keyblock, recheck, &modified );
+               if( rc ) {
+                   log_error(_("lid %lu: update failed: %s\n"),
+                                                recnum, g10_errstr(rc) );
+                   err_count++;
+               }
+               else if( modified ) {
+                   if( opt.verbose )
+                       log_info(_("lid %lu: updated\n"), recnum );
+                   upd_count++;
+               }
+               else if( opt.verbose > 1 )
+                   log_info(_("lid %lu: okay\n"), recnum );
+
+               release_kbnode( keyblock ); keyblock = NULL;
+               if( !(++count % 100) )
+                   log_info(_("%lu keys so far processed\n"), count);
+           }
+       }
+       log_info(_("%lu keys processed\n"), count);
+       if( skip_count )
+           log_info(_("\t%lu keys skipped\n"), skip_count);
+       if( err_count )
+           log_info(_("\t%lu keys with errors\n"), err_count);
+       if( upd_count )
+           log_info(_("\t%lu keys updated\n"), upd_count);
+    }
+}
+
+
+/****************
+ * Put new entries  from the pubrings into the trustdb.
+ * This function honors the sig flags to speed up the check.
+ */
+void
+update_trustdb( )
+{
+    KBNODE keyblock = NULL;
+    KBPOS kbpos;
+    int rc;
+
+    rc = enum_keyblocks( 0, &kbpos, &keyblock );
+    if( !rc ) {
+       ulong count=0, upd_count=0, err_count=0, new_count=0;
+
+       while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
+           int modified;
+
+           rc = update_trust_record( keyblock, 1, &modified );
+           if( rc == -1 ) { /* not yet in trustdb: insert */
+               PKT_public_key *pk =
+                           find_kbnode( keyblock, PKT_PUBLIC_KEY
+                                      ) ->pkt->pkt.public_key;
+               rc = insert_trust_record( pk );
+               if( rc && !pk->local_id ) {
+                   log_error(_("lid ?: insert failed: %s\n"),
+                                                    g10_errstr(rc) );
+                   err_count++;
+               }
+               else if( rc ) {
+                   log_error(_("lid %lu: insert failed: %s\n"),
+                                      pk->local_id, g10_errstr(rc) );
+                   err_count++;
+               }
+               else {
+                   if( opt.verbose )
+                       log_info(_("lid %lu: inserted\n"), pk->local_id );
+                   new_count++;
+               }
+           }
+           else if( rc ) {
+               log_error(_("lid %lu: update failed: %s\n"),
+                        lid_from_keyblock(keyblock), g10_errstr(rc) );
+               err_count++;
+           }
+           else if( modified ) {
+               if( opt.verbose )
+                   log_info(_("lid %lu: updated\n"), lid_from_keyblock(keyblock));
+               upd_count++;
+           }
+           else if( opt.verbose > 1 )
+               log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) );
 
-    free_public_cert( pkc );
+           release_kbnode( keyblock ); keyblock = NULL;
+           if( !(++count % 100) )
+               log_info(_("%lu keys so far processed\n"), count);
+       }
+       log_info(_("%lu keys processed\n"), count);
+       if( err_count )
+           log_info(_("\t%lu keys with errors\n"), err_count);
+       if( upd_count )
+           log_info(_("\t%lu keys updated\n"), upd_count);
+       if( new_count )
+           log_info(_("\t%lu keys inserted\n"), new_count);
+    }
+    if( rc && rc != -1 )
+       log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
+
+    enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+    release_kbnode( keyblock );
 }
 
 
+\f
 /****************
- * Get the trustlevel for this PKC.
+ * Get the trustlevel for this PK.
  * Note: This does not ask any questions
  * Returns: 0 okay of an errorcode
  *
  * It operates this way:
- *  locate the pkc in the trustdb
+ *  locate the pk in the trustdb
  *     found:
  *         Do we have a valid cache record for it?
  *             yes: return trustlevel from cache
  *             no:  make a cache record and all the other stuff
  *     not found:
- *         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.
+ *         try to insert the pubkey into the trustdb and check again
  *
  * Problems: How do we get the complete keyblock to check that the
  *          cache record is actually valid?  Think we need a clever
@@ -1700,57 +1579,59 @@ list_trust_path( int max_depth, const char *username )
  *          is not necessary to check this if we use a local pubring. Hmmmm.
  */
 int
-check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel )
+check_trust( PKT_public_key *pk, unsigned *r_trustlevel )
 {
     TRUSTREC rec;
     unsigned trustlevel = TRUST_UNKNOWN;
     int rc=0;
-    int cur_time;
+    u32 cur_time;
+    u32 keyid[2];
 
-    if( DBG_TRUST )
-       log_info("check_trust() called.\n");
+
+    keyid_from_pk( pk, keyid );
 
     /* get the pubkey record */
-    if( pkc->local_id ) {
-       if( read_record( pkc->local_id, &rec, RECTYPE_DIR ) ) {
-           log_error(_("check_trust: read record failed\n"));
-           return G10ERR_TRUSTDB;
-       }
+    if( pk->local_id ) {
+       read_record( pk->local_id, &rec, RECTYPE_DIR );
     }
     else { /* no local_id: scan the trustdb */
-       if( (rc=search_record( pkc, &rec )) && rc != -1 ) {
-           log_error(_("check_trust: search_record failed: %s\n"),
+       if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 ) {
+           log_error(_("check_trust: search dir record failed: %s\n"),
                                                            g10_errstr(rc));
            return rc;
        }
-       else if( rc == -1 ) {
-           rc = insert_trust_record( pkc );
+       else if( rc == -1 ) { /* not found - insert */
+           rc = insert_trust_record( pk );
            if( rc ) {
-               log_error(_("failed to insert pubkey into trustdb: %s\n"),
-                                                           g10_errstr(rc));
+               log_error(_("key %08lX: insert trust record failed: %s\n"),
+                                         (ulong)keyid[1], g10_errstr(rc));
                goto leave;
            }
-           log_info(_("pubkey not in trustdb - inserted as %lu\n"),
-                                   pkc->local_id );
+           log_info(_("key %08lX.%lu: inserted into trustdb\n"),
+                                         (ulong)keyid[1], pk->local_id );
+           /* and re-read the dir record */
+           read_record( pk->local_id, &rec, RECTYPE_DIR );
        }
     }
     cur_time = make_timestamp();
-    if( pkc->timestamp > cur_time ) {
-       log_info(_("public key created in future (time warp or clock problem)\n"));
+    if( pk->timestamp > cur_time ) {
+       log_info(_("key %08lX.%lu: created in future "
+                  "(time warp or clock problem)\n"),
+                                         (ulong)keyid[1], pk->local_id );
        return G10ERR_TIME_CONFLICT;
     }
 
-    if( pkc->valid_days && add_days_to_timestamp(pkc->timestamp,
-                                               pkc->valid_days) < cur_time ) {
-       log_info(_("key expiration date is %s\n"), strtimestamp(
-                                   add_days_to_timestamp(pkc->timestamp,
-                                                         pkc->valid_days)));
+    if( pk->expiredate && pk->expiredate <= cur_time ) {
+       log_info(_("key %08lX.%lu: expired at %s\n"),
+                       (ulong)keyid[1], pk->local_id,
+                            asctimestamp( pk->expiredate) );
         trustlevel = TRUST_EXPIRED;
     }
     else {
-       rc = do_check( pkc->local_id, &rec, &trustlevel );
+       rc = do_check( &rec, &trustlevel );
        if( rc ) {
-           log_error(_("check_trust: do_check failed: %s\n"), g10_errstr(rc));
+           log_error(_("key %08lX.%lu: trust check failed: %s\n"),
+                           (ulong)keyid[1], pk->local_id, g10_errstr(rc));
            return rc;
        }
     }
@@ -1758,32 +1639,27 @@ check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel )
 
   leave:
     if( DBG_TRUST )
-       log_info("check_trust() returns trustlevel %04x.\n", trustlevel);
+       log_debug("check_trust() returns trustlevel %04x.\n", trustlevel);
     *r_trustlevel = trustlevel;
     return 0;
 }
 
 
+
+
 int
-query_trust_info( PKT_public_cert *pkc )
+query_trust_info( PKT_public_key *pk )
 {
     unsigned trustlevel;
     int c;
 
-    if( check_trust( pkc, &trustlevel ) )
+    if( check_trust( pk, &trustlevel ) )
        return '?';
     if( trustlevel & TRUST_FLAG_REVOKED )
        return 'r';
-    switch( (trustlevel & TRUST_MASK) ) {
-      case TRUST_UNKNOWN:   c = 'o'; break;
-      case TRUST_EXPIRED:   c = 'e'; break;
-      case TRUST_UNDEFINED: c = 'q'; break;
-      case TRUST_NEVER:     c = 'n'; break;
-      case TRUST_MARGINAL:  c = 'm'; break;
-      case TRUST_FULLY:     c = 'f'; break;
-      case TRUST_ULTIMATE:  c = 'u'; break;
-      default: BUG();
-    }
+    c = trust_letter( (trustlevel & TRUST_MASK) );
+    if( !c )
+       c = '?';
     return c;
 }
 
@@ -1792,7 +1668,10 @@ query_trust_info( PKT_public_cert *pkc )
 /****************
  * Enumerate all keys, which are needed to build all trust paths for
  * the given key.  This function does not return the key itself or
- * the ultimate key.
+ * the 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.
@@ -1801,261 +1680,1460 @@ query_trust_info( PKT_public_cert *pkc )
  *     to indicate EOF. LID does contain the next key used to build the web
  *  4) Always call this function a last time with LID set to NULL,
  *     so that it can free its context.
+ *
+ * Returns: -1 on EOF or the level of the returned LID
  */
 int
-enum_trust_web( void **context, ulong *lid )
+enum_cert_paths( void **context, ulong *lid,
+                unsigned *ownertrust, unsigned *validity )
 {
-    ENUM_TRUST_WEB_CONTEXT *c = *context;
+    struct enum_cert_paths_ctx *ctx;
+    TRUST_SEG_LIST tsl;
+
+    if( !lid ) {  /* release the context */
+       if( *context ) {
+           TRUST_SEG_LIST tsl2;
 
-    if( !c ) { /* make a new context */
-       c = m_alloc_clear( sizeof *c );
-       *context = c;
-       if( *lid != last_trust_web_key && last_trust_web_key )
-           log_bug("enum_trust_web: nyi\n"); /* <--- FIXME */
-       c->tsl = last_trust_web_tslist;
-       c->index = 1;
+           ctx = *context;
+           for(tsl = ctx->tsl_head; tsl; tsl = tsl2 ) {
+               tsl2 = tsl->next;
+               m_free( tsl );
+           }
+           *context = NULL;
+       }
+       return -1;
     }
 
-    if( !lid ) { /* free the context */
-       m_free( c );
-       *context = NULL;
-       return 0;
+    if( !*context ) {
+       TRUST_INFO *tmppath;
+       TRUSTREC rec;
+
+       if( !*lid )
+           return -1;
+
+       ctx = m_alloc_clear( sizeof *ctx );
+       *context = ctx;
+       /* collect the paths */
+       read_record( *lid, &rec, RECTYPE_DIR );
+       tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
+       tsl = NULL;
+       collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &tsl );
+       m_free( tmppath );
+       sort_tsl_list( &tsl );
+       /* setup the context */
+       ctx->tsl_head = tsl;
+       ctx->tsl = ctx->tsl_head;
+       ctx->idx = 0;
     }
+    else
+       ctx = *context;
 
-    while( c->tsl ) {
-       if( !c->tsl->dup && c->index < c->tsl->nseg-1 ) {
-           *lid = c->tsl->seg[c->index].lid;
-           c->index++;
-           return 0;
+    while( ctx->tsl && ctx->idx >= ctx->tsl->pathlen ) {
+       ctx->tsl = ctx->tsl->next;
+       ctx->idx = 0;
+    }
+    tsl = ctx->tsl;
+    if( !tsl )
+       return -1; /* eof */
+
+    if( ownertrust )
+       *ownertrust = tsl->path[ctx->idx].otrust;
+    if( validity )
+       *validity = tsl->path[ctx->idx].trust;
+    *lid = tsl->path[ctx->idx].lid;
+    ctx->idx++;
+    return ctx->idx-1;
+}
+
+
+/****************
+ * Print the current path
+ */
+void
+enum_cert_paths_print( void **context, FILE *fp,
+                                      int refresh, ulong selected_lid )
+{
+    struct enum_cert_paths_ctx *ctx;
+    TRUST_SEG_LIST tsl;
+
+    if( !*context )
+       return;
+    ctx = *context;
+    if( !ctx->tsl )
+       return;
+    tsl = ctx->tsl;
+
+    if( !fp )
+       fp = stderr;
+
+    if( refresh ) { /* update the ownertrust and if possible the validity */
+       int i;
+       int match = tdbio_db_matches_options();
+
+       for( i = 0; i < tsl->pathlen; i++ )  {
+           TRUSTREC rec;
+
+           read_record( tsl->path[i].lid, &rec, RECTYPE_DIR );
+           tsl->path[i].otrust = rec.r.dir.ownertrust;
+           /* update validity only if we have it in the cache
+            * calculation is too time consuming */
+           if( match && (rec.r.dir.dirflags & DIRF_VALVALID)
+                     && rec.r.dir.validity ) {
+               tsl->path[i].trust = rec.r.dir.validity;
+               if( rec.r.dir.dirflags & DIRF_REVOKED )
+                   tsl->path[i].trust = TRUST_FLAG_REVOKED;
+           }
        }
-       c->index = 1;
-       c->tsl = c->tsl->next;
     }
-    return -1; /* eof */
+
+    print_path( tsl->pathlen, tsl->path, fp, selected_lid );
 }
 
 
 /****************
  * Return the assigned ownertrust value for the given LID
  */
-int
-get_ownertrust( ulong lid, unsigned *r_otrust )
+unsigned
+get_ownertrust( ulong lid )
 {
     TRUSTREC rec;
 
-    if( read_record( lid, &rec, RECTYPE_DIR ) ) {
-       log_error("get_ownertrust: read dir record failed\n");
-       return G10ERR_TRUSTDB;
-    }
-    if( read_record( rec.r.dir.keyrec, &rec, RECTYPE_KEY ) ) {
-       log_error("get_ownertrust: read key record failed\n");
-       return G10ERR_TRUSTDB;
+    read_record( lid, &rec, RECTYPE_DIR );
+    return rec.r.dir.ownertrust;
+}
+
+int
+get_ownertrust_info( ulong lid )
+{
+    unsigned otrust;
+    int c;
+
+    otrust = get_ownertrust( lid );
+    c = trust_letter( (otrust & TRUST_MASK) );
+    if( !c )
+       c = '?';
+    return c;
+}
+
+/*
+ * Return an allocated buffer with the preference values for
+ * the key with LID and the userid which is identified by the
+ * HAMEHASH or the firstone if namehash is NULL.  ret_n receives
+ * the length of the allcoated buffer. Structure of the buffer is
+ * a repeated sequences of 2 bytes; where the first byte describes the
+ * type of the preference and the second one the value.  The constants
+ * PREFTYPE_xxxx should be used to reference a type.
+ */
+byte *
+get_pref_data( ulong lid, const byte *namehash, size_t *ret_n )
+{
+    TRUSTREC rec;
+    ulong recno;
+
+    read_record( lid, &rec, RECTYPE_DIR );
+    for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
+       read_record( recno, &rec, RECTYPE_UID );
+       if( rec.r.uid.prefrec
+           && ( !namehash || !memcmp(namehash, rec.r.uid.namehash, 20) ))  {
+           byte *buf;
+           /* found the correct one or the first one */
+           read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
+           if( rec.r.pref.next )
+               log_info(_("WARNING: can't yet handle long pref records\n"));
+           buf = m_alloc( ITEMS_PER_PREF_RECORD );
+           memcpy( buf, rec.r.pref.data, ITEMS_PER_PREF_RECORD );
+           *ret_n = ITEMS_PER_PREF_RECORD;
+           return buf;
+       }
     }
-    if( r_otrust )
-       *r_otrust = rec.r.key.ownertrust;
-    return 0;
+    return NULL;
 }
 
+
+
+/****************
+ * Check whether the algorithm is in one of the pref records
+ */
 int
-keyid_from_trustdb( ulong lid, u32 *keyid )
+is_algo_in_prefs( ulong lid, int preftype, int algo )
 {
     TRUSTREC rec;
+    ulong recno;
+    int i;
+    byte *pref;
+
+    read_record( lid, &rec, RECTYPE_DIR );
+    for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
+       read_record( recno, &rec, RECTYPE_UID );
+       if( rec.r.uid.prefrec ) {
+           read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
+           if( rec.r.pref.next )
+               log_info(_("WARNING: can't yet handle long pref records\n"));
+           pref = rec.r.pref.data;
+           for(i=0; i+1 < ITEMS_PER_PREF_RECORD; i+=2 ) {
+               if( pref[i] == preftype && pref[i+1] == algo )
+                   return 1;
+           }
+       }
+    }
+    return 0;
+}
 
-    if( read_record( lid, &rec, RECTYPE_DIR ) ) {
-       log_error("keyid_from_trustdb: read record failed\n");
-       return G10ERR_TRUSTDB;
+
+static int
+get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
+{
+    int rc=0;
+
+    if( pk->local_id ) {
+       read_record( pk->local_id, rec, RECTYPE_DIR );
     }
-    if( keyid ) {
-       keyid[0] = rec.r.dir.keyid[0];
-       keyid[1] = rec.r.dir.keyid[1];
+    else { /* no local_id: scan the trustdb */
+       if( (rc=tdbio_search_dir_bypk( pk, rec )) && rc != -1 )
+           log_error(_("get_dir_record: search_record failed: %s\n"),
+                                                           g10_errstr(rc));
     }
-    return 0;
+    return rc;
 }
 
 
+
 /****************
  * This function simply looks for the key in the trustdb
- * and sets PKC->local_id.
+ * and makes sure that pk->local_id is set to the correct value.
  * Return: 0 = found
  *        -1 = not found
  *       other = error
  */
 int
-query_trust_record( PKT_public_cert *pkc )
+query_trust_record( PKT_public_key *pk )
 {
     TRUSTREC rec;
-    int rc=0;
+    return get_dir_record( pk, &rec );
+}
+
+
+int
+clear_trust_checked_flag( PKT_public_key *pk )
+{
+    TRUSTREC rec;
+    int rc;
+
+    rc = get_dir_record( pk, &rec );
+    if( rc )
+       return rc;
+
+    /* check whether they are already reset */
+    if(   !(rec.r.dir.dirflags & DIRF_CHECKED)
+       && !(rec.r.dir.dirflags & DIRF_VALVALID) )
+       return 0;
 
-    if( pkc->local_id ) {
-       if( read_record( pkc->local_id, &rec, RECTYPE_DIR ) ) {
-           log_error("query_trust_record: read record failed\n");
-           return G10ERR_TRUSTDB;
+    /* reset the flag */
+    rec.r.dir.dirflags &= ~DIRF_CHECKED;
+    rec.r.dir.dirflags &= ~DIRF_VALVALID;
+    write_record( &rec );
+    do_sync();
+    return 0;
+}
+
+
+
+
+static void
+check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
+               TRUSTREC *sigrec, int sigidx, ulong hint_owner )
+{
+    KBNODE node;
+    int rc, state;
+    byte uhash[20];
+    int is_selfsig;
+    PKT_signature *sigpkt = NULL;
+    TRUSTREC tmp;
+    u32 sigkid[2];
+    int revoke = 0;
+
+    if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED )
+       log_info(_("NOTE: sig rec %lu[%d] in hintlist "
+                  "of %lu but marked as checked\n"),
+                   sigrec->recnum, sigidx, hint_owner );
+    if( !(sigrec->r.sig.sig[sigidx].flag & SIGF_NOPUBKEY) )
+       log_info(_("NOTE: sig rec %lu[%d] in hintlist "
+                  "of %lu but not marked\n"),
+                   sigrec->recnum, sigidx, hint_owner );
+
+    read_record( sigrec->r.sig.sig[sigidx].lid, &tmp, 0 );
+    if( tmp.rectype != RECTYPE_DIR ) {
+       /* we need the dir record */
+       log_error(_("sig rec %lu[%d] in hintlist "
+                   "of %lu does not point to a dir record\n"),
+                   sigrec->recnum, sigidx, hint_owner );
+       return;
+    }
+    if( !tmp.r.dir.keylist ) {
+       log_error(_("lid %lu: no primary key\n"), tmp.r.dir.lid );
+       return;
+    }
+    read_record(tmp.r.dir.keylist, &tmp, RECTYPE_KEY );
+    keyid_from_fingerprint( tmp.r.key.fingerprint,
+                           tmp.r.key.fingerprint_len, sigkid );
+
+
+    /* find the correct signature packet */
+    state = 0;
+    for( node=keyblock; node; node = node->next ) {
+       if( node->pkt->pkttype == PKT_USER_ID ) {
+           PKT_user_id *uidpkt = node->pkt->pkt.user_id;
+
+           if( state )
+               break;
+           rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
+           if( !memcmp( uhash, uidrec_hash, 20 ) )
+               state = 1;
        }
-    }
-    else { /* no local_id: scan the trustdb */
-       if( (rc=search_record( pkc, &rec )) && rc != -1 ) {
-           log_error("query_trust_record: search_record failed: %s\n",
-                                                           g10_errstr(rc));
-           return rc;
+       else if( state && node->pkt->pkttype == PKT_SIGNATURE ) {
+           sigpkt = node->pkt->pkt.signature;
+           if( sigpkt->keyid[0] == sigkid[0]
+               && sigpkt->keyid[1] == sigkid[1]
+               && ( (sigpkt->sig_class&~3) == 0x10
+                    || ( revoke = (sigpkt->sig_class == 0x30)) ) ) {
+               state = 2;
+               break; /* found */
+           }
        }
     }
-    return rc;
+
+    if( !node ) {
+       log_info(_("lid %lu: user id not found in keyblock\n"), lid );
+       return ;
+    }
+    if( state != 2 ) {
+       log_info(_("lid %lu: user id without signature\n"), lid );
+       return ;
+    }
+
+    /* and check the sig */
+    rc = check_key_signature( keyblock, node, &is_selfsig );
+    if( is_selfsig ) {
+       log_error(_("lid %lu: self-signature in hintlist\n"), lid );
+       return;
+    }
+
+    /* FiXME: handling fo SIGF_REVOKED is not correct! */
+
+    if( !rc ) { /* valid signature */
+       if( opt.verbose )
+           log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+                   (ulong)keyid[1], lid, uhash[18], uhash[19],
+                   (ulong)sigpkt->keyid[1],
+                   revoke? _("Valid certificate revocation")
+                         : _("Good certificate") );
+       sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
+       if( revoke )
+           sigrec->r.sig.sig[sigidx].flag |= SIGF_REVOKED;
+    }
+    else if( rc == G10ERR_NO_PUBKEY ) {
+       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+             (ulong)keyid[1], lid, uhash[18], uhash[19],
+              (ulong)sigpkt->keyid[1],
+                _("very strange: no public key\n") );
+       sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY;
+    }
+    else {
+       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+                   (ulong)keyid[1], lid, uhash[18], uhash[19],
+                   (ulong)sigpkt->keyid[1], g10_errstr(rc) );
+       sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED;
+    }
+    sigrec->dirty = 1;
 }
 
 
 /****************
- * Insert a trust record into the TrustDB
- * This function fails if this record already exists.
+ * Process a hintlist.
+ * Fixme: this list is not anymore anchored to another
+ *       record, so it should be put elsewehere in case of an error
  */
-int
-insert_trust_record( PKT_public_cert *pkc )
+static void
+process_hintlist( ulong hintlist, ulong hint_owner )
 {
-    TRUSTREC rec;
-    u32 keyid[2];
-    ulong knum, dnum;
-    byte *fingerprint;
-    size_t fingerlen;
+    ulong hlst_rn;
+    int rc;
 
+    for( hlst_rn = hintlist; hlst_rn; ) {
+       TRUSTREC hlstrec;
+       int hlst_idx;
 
-    if( pkc->local_id )
-       log_bug("pkc->local_id=%lu\n", (ulong)pkc->local_id );
+       read_record( hlst_rn, &hlstrec, RECTYPE_HLST );
 
-    keyid_from_pkc( pkc, keyid );
-    fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
+       for( hlst_idx=0; hlst_idx < ITEMS_PER_HLST_RECORD; hlst_idx++ ) {
+           TRUSTREC dirrec;
+           TRUSTREC uidrec;
+           TRUSTREC tmprec;
+           KBNODE keyblock = NULL;
+           u32 keyid[2];
+           ulong lid;
+           ulong r1, r2;
 
-    /* FIXME: check that we do not have this record. */
+           lid = hlstrec.r.hlst.rnum[hlst_idx];
+           if( !lid )
+               continue;
 
-    dnum = new_recnum();
-    knum = new_recnum();
-    /* build dir record */
-    memset( &rec, 0, sizeof rec );
-    rec.rectype = RECTYPE_DIR;
-    rec.r.dir.local_id = dnum;
-    rec.r.dir.keyid[0] = keyid[0];
-    rec.r.dir.keyid[1] = keyid[1];
-    rec.r.dir.keyrec   = knum;
-    rec.r.dir.no_sigs = 0;
-    if( write_record( dnum, &rec ) ) {
-       log_error("writing dir record failed\n");
-       return G10ERR_TRUSTDB;
+           read_record( lid, &dirrec, 0 );
+           /* make sure it points to a dir record:
+            * this should be true because it only makes sense to
+            * call this function if the dir record is available */
+           if( dirrec.rectype != RECTYPE_DIR )  {
+               log_error(_("hintlist %lu[%d] of %lu "
+                           "does not point to a dir record\n"),
+                           hlst_rn, hlst_idx, hint_owner );
+               continue;
+           }
+           if( !dirrec.r.dir.keylist ) {
+               log_error(_("lid %lu does not have a key\n"), lid );
+               continue;
+           }
+
+           /* get the keyblock */
+           read_record( dirrec.r.dir.keylist, &tmprec, RECTYPE_KEY );
+           rc = get_keyblock_byfprint( &keyblock,
+                                       tmprec.r.key.fingerprint,
+                                       tmprec.r.key.fingerprint_len );
+           if( rc ) {
+               log_error(_("lid %lu: can't get keyblock: %s\n"),
+                                                   lid, g10_errstr(rc) );
+               continue;
+           }
+           keyid_from_fingerprint( tmprec.r.key.fingerprint,
+                                   tmprec.r.key.fingerprint_len, keyid );
+
+           /* Walk over all user ids and their signatures and check all
+            * the signature which are created by hint_owner */
+           for( r1 = dirrec.r.dir.uidlist; r1; r1 = uidrec.r.uid.next ) {
+               TRUSTREC sigrec;
+
+               read_record( r1, &uidrec, RECTYPE_UID );
+               for( r2 = uidrec.r.uid.siglist; r2; r2 = sigrec.r.sig.next ) {
+                   int i;
+
+                   read_record( r2, &sigrec, RECTYPE_SIG );
+                   sigrec.dirty = 0;
+                   for(i=0; i < SIGS_PER_RECORD; i++ ) {
+                       if( !sigrec.r.sig.sig[i].lid )
+                           continue; /* skip deleted sigs */
+                       if( sigrec.r.sig.sig[i].lid != hint_owner )
+                           continue; /* not for us */
+                       /* some diagnostic messages */
+                       /* and do the signature check */
+                       check_hint_sig( lid, keyblock, keyid,
+                                       uidrec.r.uid.namehash,
+                                       &sigrec, i, hint_owner );
+                   }
+                   if( sigrec.dirty )
+                       write_record( &sigrec );
+               }
+           }
+           release_kbnode( keyblock );
+       } /* loop over hlst entries */
+
+       /* delete this hlst record */
+       hlst_rn = hlstrec.r.hlst.next;
+       delete_record( hlstrec.recnum );
+    } /* loop over hintlist */
+}
+
+
+/****************
+ * Create or update shadow dir record and return the LID of the record
+ */
+static ulong
+create_shadow_dir( PKT_signature *sig, ulong lid  )
+{
+    TRUSTREC sdir, hlst, tmphlst;
+    ulong recno, newlid;
+    int tmpidx=0; /* avoids gcc warnign - this is controlled by tmphlst */
+    int rc;
+
+    /* first see whether we already have such a record */
+    rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir );
+    if( rc && rc != -1 ) {
+       log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
+       die_invalid_db();
+    }
+    if( rc == -1 ) { /* not found: create */
+       memset( &sdir, 0, sizeof sdir );
+       sdir.recnum = tdbio_new_recnum();
+       sdir.rectype= RECTYPE_SDIR;
+       sdir.r.sdir.lid = sdir.recnum;
+       sdir.r.sdir.keyid[0] = sig->keyid[0];
+       sdir.r.sdir.keyid[1] = sig->keyid[1];
+       sdir.r.sdir.pubkey_algo = sig->pubkey_algo;
+       sdir.r.sdir.hintlist = 0;
+       write_record( &sdir );
+    }
+    newlid = sdir.recnum;
+    /* Put the record number into the hintlist.
+     * (It is easier to use the lid and not the record number of the
+     * key to save some space (assuming that a signator has
+     * signed more than one user id - and it is easier to implement.)
+     */
+    tmphlst.recnum = 0;
+    for( recno=sdir.r.sdir.hintlist; recno; recno = hlst.r.hlst.next) {
+       int i;
+       read_record( recno, &hlst, RECTYPE_HLST );
+       for( i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
+           if( !hlst.r.hlst.rnum[i] ) {
+               if( !tmphlst.recnum ) {
+                   tmphlst = hlst;
+                   tmpidx = i;
+               }
+           }
+           else if( hlst.r.hlst.rnum[i] == lid )
+               return newlid; /* the signature is already in the hintlist */
+       }
     }
-    /* and the key record */
-    memset( &rec, 0, sizeof rec );
-    rec.rectype = RECTYPE_KEY;
-    rec.r.key.owner    = dnum;
-    rec.r.key.keyid[0] = keyid[0];
-    rec.r.key.keyid[1] = keyid[1];
-    rec.r.key.pubkey_algo = pkc->pubkey_algo;
-    rec.r.key.fingerprint_len = fingerlen;
-    memcpy(rec.r.key.fingerprint, fingerprint, fingerlen );
-    rec.r.key.ownertrust = 0;
-    if( write_record( knum, &rec ) ) {
-       log_error("wrinting key record failed\n");
-       return G10ERR_TRUSTDB;
+    /* not yet in the hint list, write it */
+    if( tmphlst.recnum ) { /* we have an empty slot */
+       tmphlst.r.hlst.rnum[tmpidx] = lid;
+       write_record( &tmphlst );
+    }
+    else { /* must append a new hlst record */
+       memset( &hlst, 0, sizeof hlst );
+       hlst.recnum = tdbio_new_recnum();
+       hlst.rectype = RECTYPE_HLST;
+       hlst.r.hlst.next = sdir.r.sdir.hintlist;
+       hlst.r.hlst.rnum[0] = lid;
+       write_record( &hlst );
+       sdir.r.sdir.hintlist = hlst.recnum;
+       write_record( &sdir );
     }
 
-    pkc->local_id = dnum;
-
-    return 0;
+    return newlid;
 }
 
 
-int
-update_ownertrust( ulong lid, unsigned new_trust )
+/****************
+ * This function checks the given public key and inserts or updates
+ * the keyrecord from the trustdb.  Revocation certificates
+ * are handled here and the keybinding of subkeys is checked.
+ * Hmmm: Should we check here, that the key has at least one valid
+ * user ID or do we allow keys w/o user ID?
+ *
+ * keyblock points to the first node in the keyblock,
+ * keynode is the node with the public key to check
+ * (either primary or secondary), keyid is the keyid of
+ * the primary key, drec is the directory record and recno_list
+ * is a list used to keep track of visited records.
+ * Existing keyflags are recalculated if recheck is true.
+ */
+static void
+upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
+               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
 {
-    TRUSTREC rec;
-    ulong recnum;
+    TRUSTREC krec;
+    KBNODE  node;
+    PKT_public_key *pk = keynode->pkt->pkt.public_key;
+    ulong lid = drec->recnum;
+    byte fpr[MAX_FINGERPRINT_LEN];
+    size_t fprlen;
+    ulong recno, newrecno;
+    int keybind_seen = 0;
+    int revoke_seen = 0;
+    int rc;
 
-    if( read_record( lid, &rec, RECTYPE_DIR ) ) {
-       log_error("update_ownertrust: read dir failed\n");
-       return G10ERR_TRUSTDB;
+    fingerprint_from_pk( pk, fpr, &fprlen );
+    /* do we already have this key? */
+    for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) {
+       read_record( recno, &krec, RECTYPE_KEY );
+       if( krec.r.key.fingerprint_len == fprlen
+           && !memcmp( krec.r.key.fingerprint, fpr, fprlen ) )
+           break;
     }
-    recnum = rec.r.dir.keyrec;
-    if( read_record( recnum, &rec, RECTYPE_KEY ) ) {
-       log_error("update_ownertrust: read key failed\n");
-       return G10ERR_TRUSTDB;
+    if( recno ) { /* yes */
+       ins_recno_list( recno_list, recno, RECTYPE_KEY );
+    }
+    else { /* no: insert this new key */
+       recheck = 1;
+       memset( &krec, 0, sizeof(krec) );
+       krec.rectype = RECTYPE_KEY;
+       krec.r.key.lid = lid;
+       krec.r.key.pubkey_algo = pk->pubkey_algo;
+       krec.r.key.fingerprint_len = fprlen;
+       memcpy(krec.r.key.fingerprint, fpr, fprlen );
+       krec.recnum = newrecno = tdbio_new_recnum();
+       write_record( &krec );
+       ins_recno_list( recno_list, newrecno, RECTYPE_KEY );
+       /* and put this new record at the end of the keylist */
+       if( !(recno=drec->r.dir.keylist) ) {
+           /* this is the first key */
+           drec->r.dir.keylist = newrecno;
+           drec->dirty = 1;
+       }
+       else { /* we already have a key, append the new one */
+           TRUSTREC save = krec;
+           for( ; recno; recno = krec.r.key.next )
+               read_record( recno, &krec, RECTYPE_KEY );
+           krec.r.key.next = newrecno;
+           write_record( &krec );
+           krec = save;
+       }
     }
-    /* check keyid, fingerprint etc ? */
 
-    rec.r.key.ownertrust = new_trust;
-    if( write_record( recnum, &rec ) ) {
-       log_error("update_ownertrust: write failed\n");
-       return G10ERR_TRUSTDB;
+    if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) )
+       return;
+
+    /* check keybindings and revocations */
+    krec.r.key.keyflags = 0;
+    if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) {
+       /* we assume that a primary key is always valid
+        * and check later whether we have a revocation */
+       krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
     }
 
-    return 0;
+    for( node=keynode->next; node; node = node->next ) {
+       PKT_signature *sig;
+
+       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+           break; /* ready */
+       else if( node->pkt->pkttype != PKT_SIGNATURE )
+           continue;
+
+       sig = node->pkt->pkt.signature;
+
+       if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
+           continue; /* not a self signature */
+       if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
+           if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
+               continue; /* oops, not for a main key */
+           /* we check until we find a valid keybinding */
+           rc = check_key_signature( keyblock, node, NULL );
+           if( !rc ) {
+               if( opt.verbose )
+                   log_info(_(
+                       "key %08lX.%lu: Good subkey binding\n"),
+                        (ulong)keyid_from_pk(pk,NULL), lid );
+               krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
+           }
+           else {
+               log_info(_(
+                 "key %08lX.%lu: Invalid subkey binding: %s\n"),
+                   (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+               krec.r.key.keyflags |= KEYF_CHECKED;
+               krec.r.key.keyflags &= ~KEYF_VALID;
+           }
+           keybind_seen = 1;
+       }
+       else if( sig->sig_class == 0x20 && !revoke_seen ) {
+           if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+               continue; /* a subkey is not expected here */
+           /* This is a key revocation certificate: check it */
+           rc = check_key_signature( keyblock, node, NULL );
+           if( !rc ) {
+               if( opt.verbose )
+                   log_info(_(
+                       "key %08lX.%lu: Valid key revocation\n"),
+                        (ulong)keyid_from_pk(pk,NULL), lid );
+               krec.r.key.keyflags |= KEYF_REVOKED;
+           }
+           else {
+               log_info(_(
+                 "key %08lX.%lu: Invalid key revocation: %s\n"),
+                 (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+           }
+           revoke_seen = 1;
+       }
+       else if( sig->sig_class == 0x28 && !revoke_seen ) {
+           if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
+               continue; /* a mainkey is not expected here */
+           /* This is a subkey revocation certificate: check it */
+           /* fixme: we should also check the revocation
+            * is newer than the key (OpenPGP) */
+           rc = check_key_signature( keyblock, node, NULL );
+           if( !rc ) {
+               if( opt.verbose )
+                   log_info(_(
+                       "key %08lX.%lu: Valid subkey revocation\n"),
+                        (ulong)keyid_from_pk(pk,NULL), lid );
+               krec.r.key.keyflags |= KEYF_REVOKED;
+           }
+           else {
+               log_info(_(
+                 "key %08lX.%lu: Invalid subkey binding: %s\n"),
+                 (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+           }
+           revoke_seen = 1;
+       }
+    }
+
+    write_record( &krec );
+}
+
+
+/****************
+ * This function checks the given user ID and inserts or updates
+ * the uid record of the trustdb.  Revocation certificates
+ * are handled here.
+ *
+ * keyblock points to the first node in the keyblock,
+ * uidnode is the node with the user id to check
+ * keyid is the keyid of
+ * the primary key, drec is the directory record and recno_list
+ * is a list used to keep track of visited records.
+ * Existing uidflags are recalculated if recheck is true.
+ */
+static void
+upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
+               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
+{
+    ulong lid = drec->recnum;
+    PKT_user_id *uid = uidnode->pkt->pkt.user_id;
+    TRUSTREC urec;
+    PKT_signature *selfsig = NULL;
+    byte uidhash[20];
+    KBNODE node;
+    ulong recno, newrecno;
+    int rc;
+
+    /* see whether we already have an uid record */
+    rmd160_hash_buffer( uidhash, uid->name, uid->len );
+    for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
+       read_record( recno, &urec, RECTYPE_UID );
+       if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) )
+           break;
+    }
+    if( recno ) { /* we already have this record */
+       ins_recno_list( recno_list, recno, RECTYPE_UID );
+    }
+    else { /* new user id */
+       recheck = 1;
+       memset( &urec, 0 , sizeof(urec) );
+       urec.rectype = RECTYPE_UID;
+       urec.r.uid.lid = drec->recnum;
+       memcpy(urec.r.uid.namehash, uidhash, 20 );
+       urec.recnum = newrecno = tdbio_new_recnum();
+       write_record( &urec );
+       ins_recno_list( recno_list, newrecno, RECTYPE_UID );
+       /* and put this new record at the end of the uidlist */
+       if( !(recno=drec->r.dir.uidlist) ) { /* this is the first uid */
+           drec->r.dir.uidlist = newrecno;
+           drec->dirty = 1;
+       }
+       else { /* we already have an uid, append it to the list */
+           TRUSTREC save = urec;
+           for( ; recno; recno = urec.r.key.next )
+               read_record( recno, &urec, RECTYPE_UID );
+           urec.r.uid.next = newrecno;
+           write_record( &urec );
+           urec = save;
+       }
+    }
+
+    if( recheck || !(urec.r.uid.uidflags & UIDF_CHECKED) ) {
+       /* check self signatures */
+       urec.r.uid.uidflags = 0;
+       for( node=uidnode->next; node; node = node->next ) {
+           PKT_signature *sig;
+
+           if( node->pkt->pkttype == PKT_USER_ID )
+               break; /* ready */
+           if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+               break; /* ready */
+           if( node->pkt->pkttype != PKT_SIGNATURE )
+               continue;
+
+           sig = node->pkt->pkt.signature;
+
+           if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
+               continue; /* not a self signature */
+
+           if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
+               rc = check_key_signature( keyblock, node, NULL );
+               if( !rc ) {
+                   if( opt.verbose )
+                       log_info( "uid %08lX.%lu/%02X%02X: %s\n",
+                          (ulong)keyid[1], lid, uidhash[18], uidhash[19],
+                                 _("Good self-signature") );
+                   urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
+                   if( !selfsig )
+                       selfsig = sig; /* use the first valid sig */
+                   else if( sig->timestamp > selfsig->timestamp
+                            && sig->sig_class >= selfsig->sig_class )
+                       selfsig = sig; /* but this one is newer */
+               }
+               else {
+                   log_info( "uid %08lX/%02X%02X: %s: %s\n",
+                              (ulong)keyid[1], uidhash[18], uidhash[19],
+                             _("Invalid self-signature"),
+                              g10_errstr(rc) );
+                   urec.r.uid.uidflags |= UIDF_CHECKED;
+               }
+           }
+           else if( sig->sig_class == 0x30 ) { /* cert revocation */
+               rc = check_key_signature( keyblock, node, NULL );
+               if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) {
+                   log_info( "uid %08lX.%lu/%02X%02X: %s\n",
+                          (ulong)keyid[1], lid, uidhash[18], uidhash[19],
+                          _("Valid user ID revocation skipped "
+                            "due to a newer self signature\n") );
+               }
+               else if( !rc ) {
+                   if( opt.verbose )
+                       log_info( "uid %08lX.%lu/%02X%02X: %s\n",
+                          (ulong)keyid[1], lid, uidhash[18], uidhash[19],
+                                _("Valid user ID revocation\n") );
+                   urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
+                   urec.r.uid.uidflags |= UIDF_REVOKED;
+               }
+               else {
+                   log_info("uid %08lX/%02X%02X: %s: %s\n",
+                               (ulong)keyid[1], uidhash[18], uidhash[19],
+                              _("Invalid user ID revocation"),
+                                                       g10_errstr(rc) );
+               }
+           }
+       }
+       write_record( &urec );
+    } /* end check self-signatures */
+
+
+    if( (urec.r.uid.uidflags & (UIDF_CHECKED|UIDF_VALID))
+       != (UIDF_CHECKED|UIDF_VALID) )
+       return; /* user ID is not valid, so no need to check more things */
+
+    /* check the preferences */
+    if( selfsig )
+       upd_pref_record( &urec, keyid, selfsig );
+
+    /* check non-self signatures */
+    for( node=uidnode->next; node; node = node->next ) {
+       PKT_signature *sig;
+
+       if( node->pkt->pkttype == PKT_USER_ID )
+           break; /* ready */
+       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+           break; /* ready */
+       if( node->pkt->pkttype != PKT_SIGNATURE )
+           continue;
+
+       sig = node->pkt->pkt.signature;
+
+       if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] )
+           continue; /* skip self signature */
+
+       if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
+           upd_cert_record( keyblock, node, keyid, drec, recno_list,
+                            recheck, &urec, uidhash, 0 );
+       }
+       else if( sig->sig_class == 0x30 ) { /* cert revocation */
+           upd_cert_record( keyblock, node, keyid, drec, recno_list,
+                            recheck, &urec, uidhash, 1 );
+       }
+    } /* end check certificates */
+
+    write_record( &urec );
 }
 
 
 
 /****************
- * Kludge to prevent duplicate build_sigrecs() due to an invalid
- * certificate (no selfsignature or something like this)
+ *
+ *
  */
-static int
-update_no_sigs( ulong lid, int no_sigs )
+static void
+upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
 {
+    static struct {
+       sigsubpkttype_t subpkttype;
+       int preftype;
+    } ptable[] = {
+       { SIGSUBPKT_PREF_SYM,   PREFTYPE_SYM    },
+       { SIGSUBPKT_PREF_HASH,  PREFTYPE_HASH   },
+       { SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR  },
+       { 0, 0 }
+    };
+    TRUSTREC prec;
+    ulong lid = urec->r.uid.lid ;
+    const byte *uidhash = urec->r.uid.namehash;
+    const byte *s;
+    size_t n;
+    int k, i;
+    ulong recno;
+    byte prefs_sig[200];
+    int n_prefs_sig = 0;
+    byte prefs_rec[200];
+    int n_prefs_rec = 0;
+
+    /* check for changed preferences */
+    for(k=0; ptable[k].subpkttype; k++ ) {
+       s = parse_sig_subpkt2( sig, ptable[k].subpkttype, &n );
+       if( s ) {
+           for( ; n; n--, s++ ) {
+               if( n_prefs_sig >= DIM(prefs_sig)-1 ) {
+                   log_info("uid %08lX.%lu/%02X%02X: %s\n",
+                             (ulong)keyid[1], lid, uidhash[18], uidhash[19],
+                             _("Too many preferences") );
+                   break;
+               }
+               prefs_sig[n_prefs_sig++] = ptable[k].preftype;
+               prefs_sig[n_prefs_sig++] = *s;
+           }
+       }
+    }
+    for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
+       read_record( recno, &prec, RECTYPE_PREF );
+       for(i = 0; i < ITEMS_PER_PREF_RECORD; i +=2 )  {
+           if( n_prefs_rec >= DIM(prefs_rec)-1 ) {
+               log_info("uid %08lX.%lu/%02X%02X: %s\n",
+                         (ulong)keyid[1], lid, uidhash[18], uidhash[19],
+                         _("Too many preference items") );
+               break;
+           }
+           if( prec.r.pref.data[i] ) {
+               prefs_rec[n_prefs_rec++] = prec.r.pref.data[i];
+               prefs_rec[n_prefs_rec++] = prec.r.pref.data[i+1];
+           }
+       }
+    }
+    if( n_prefs_sig == n_prefs_rec
+       && !memcmp( prefs_sig, prefs_rec, n_prefs_sig ) )
+       return;  /* not changed */
+
+    /* Preferences have changed:  Delete all pref records
+     * This is much simpler than checking whether we have to
+     * do update the record at all - the record cache may care about it
+     */
+    for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
+       read_record( recno, &prec, RECTYPE_PREF );
+       delete_record( recno );
+    }
+
+    if( n_prefs_sig > ITEMS_PER_PREF_RECORD )
+        log_info(_("WARNING: can't yet handle long pref records\n"));
+
+    memset( &prec, 0, sizeof prec );
+    prec.recnum = tdbio_new_recnum();
+    prec.rectype = RECTYPE_PREF;
+    prec.r.pref.lid = lid;
+    if( n_prefs_sig <= ITEMS_PER_PREF_RECORD )
+       memcpy( prec.r.pref.data, prefs_sig, n_prefs_sig );
+    else { /* need more than one pref record */
+       TRUSTREC tmp;
+       ulong nextrn;
+       int n = n_prefs_sig;
+       byte *pp = prefs_sig;
+
+       memcpy( prec.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
+       n -= ITEMS_PER_PREF_RECORD;
+       pp += ITEMS_PER_PREF_RECORD;
+       nextrn = prec.r.pref.next = tdbio_new_recnum();
+       do {
+           memset( &tmp, 0, sizeof tmp );
+           tmp.recnum = nextrn;
+           tmp.rectype = RECTYPE_PREF;
+           tmp.r.pref.lid = lid;
+           if( n <= ITEMS_PER_PREF_RECORD ) {
+               memcpy( tmp.r.pref.data, pp, n );
+               n = 0;
+           }
+           else {
+               memcpy( tmp.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
+               n -= ITEMS_PER_PREF_RECORD;
+               pp += ITEMS_PER_PREF_RECORD;
+               nextrn = tmp.r.pref.next = tdbio_new_recnum();
+           }
+           write_record( &tmp );
+       } while( n );
+    }
+    write_record( &prec );
+    urec->r.uid.prefrec = prec.recnum;
+    urec->dirty = 1;
+}
+
+
+
+static void
+upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
+                TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
+                TRUSTREC *urec, const byte *uidhash, int revoke )
+{
+    /* We simply insert the signature into the sig records but
+     * avoid duplicate ones.  We do not check them here because
+     * there is a big chance, that we import required public keys
+     * later.  The problem with this is that we must somewhere store
+     * the information about this signature (we need a record id).
+     * We do this by using the record type shadow dir, which will
+     * be converted to a dir record as soon as a new public key is
+     * inserted into the trustdb.
+     */
+    ulong lid = drec->recnum;
+    PKT_signature *sig = signode->pkt->pkt.signature;
     TRUSTREC rec;
+    ulong recno;
+    TRUSTREC delrec;
+    int delrecidx=0;
+    int newflag = 0;
+    ulong newlid = 0;
+    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+    ulong pk_lid = 0;
+    int found_sig = 0;
+    int found_delrec = 0;
+    int rc;
 
-    if( read_record( lid, &rec, RECTYPE_DIR ) ) {
-       log_error("update_no_sigs: read failed\n");
-       return G10ERR_TRUSTDB;
+    delrec.recnum = 0;
+
+    /* get the LID of the pubkey of the signature under verification */
+    rc = get_pubkey( pk, sig->keyid );
+    if( !rc ) {
+       if( pk->local_id )
+           pk_lid = pk->local_id;
+       else {
+           rc = tdbio_search_dir_bypk( pk, &rec );
+           if( !rc )
+               pk_lid = rec.recnum;
+           else if( rc == -1 ) { /* see whether there is a sdir instead */
+               u32 akid[2];
+
+               keyid_from_pk( pk, akid );
+               rc = tdbio_search_sdir( akid, pk->pubkey_algo, &rec );
+               if( !rc )
+                   pk_lid = rec.recnum;
+           }
+       }
     }
+    free_public_key( pk ); pk = NULL;
 
-    rec.r.dir.no_sigs = no_sigs;
-    if( write_record( lid, &rec ) ) {
-       log_error("update_no_sigs: write failed\n");
-       return G10ERR_TRUSTDB;
+    /* Loop over all signatures just in case one is not correctly
+     * marked. If we see the correct signature, set a flag.
+     * delete duplicate signatures (should not happen but...) */
+    for( recno = urec->r.uid.siglist; recno; recno = rec.r.sig.next ) {
+       int i;
+
+       read_record( recno, &rec, RECTYPE_SIG );
+       for(i=0; i < SIGS_PER_RECORD; i++ ) {
+           TRUSTREC tmp;
+           if( !rec.r.sig.sig[i].lid ) {
+               if( !found_delrec && !delrec.recnum ) {
+                   delrec = rec;
+                   delrecidx = i;
+                   found_delrec=1;
+               }
+               continue; /* skip deleted sigs */
+           }
+           if( rec.r.sig.sig[i].lid == pk_lid ) {
+               if( found_sig ) {
+                   log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+                             (ulong)keyid[1], lid, uidhash[18],
+                              uidhash[19], (ulong)sig->keyid[1],
+                            _("Duplicated certificate - deleted") );
+                   rec.r.sig.sig[i].lid = 0;
+                   rec.dirty = 1;
+                   continue;
+               }
+               found_sig = 1;
+           }
+           if( !recheck && !revoke && (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
+               continue; /* we already checked this signature */
+           if( !recheck && (rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
+               continue; /* we do not have the public key */
+
+           read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
+           if( tmp.rectype == RECTYPE_DIR ) {
+               /* In this case we should now be able to check the signature */
+               rc = check_key_signature( keyblock, signode, NULL );
+               if( !rc ) { /* valid signature */
+                   if( opt.verbose )
+                       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+                               (ulong)keyid[1], lid, uidhash[18],
+                               uidhash[19], (ulong)sig->keyid[1],
+                               revoke? _("Valid certificate revocation")
+                                     : _("Good certificate") );
+                   rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
+                   if( revoke )
+                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
+               }
+               else if( rc == G10ERR_NO_PUBKEY ) {
+                 #if 0 /* fixme: For some reason this really happens? */
+                   if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
+                       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+                                 (ulong)keyid[1], lid, uidhash[18],
+                                uidhash[19], (ulong)sig->keyid[1],
+                                _("Hmmm, public key lost?") );
+                 #endif
+                   rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
+                   if( revoke )
+                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
+               }
+               else {
+                   log_info("sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
+                               (ulong)keyid[1], lid, uidhash[18],
+                               uidhash[19], (ulong)sig->keyid[1],
+                               revoke? _("Invalid certificate revocation")
+                                     : _("Invalid certificate"),
+                                                   g10_errstr(rc));
+                   rec.r.sig.sig[i].flag = SIGF_CHECKED;
+                   if( revoke )
+                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
+               }
+               rec.dirty = 1;
+           }
+           else if( tmp.rectype == RECTYPE_SDIR ) {
+               /* must check that it is the right one */
+               if( tmp.r.sdir.keyid[0] == sig->keyid[0]
+                   && tmp.r.sdir.keyid[1] == sig->keyid[1]
+                   && (!tmp.r.sdir.pubkey_algo
+                        || tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) {
+                   if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
+                       log_info(_("uid %08lX.%lu/%02X%02X: "
+                               "has shadow dir %lu but is not yet marked.\n"),
+                               (ulong)keyid[1], lid,
+                               uidhash[18], uidhash[19], tmp.recnum );
+                   rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
+                   if( revoke )
+                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
+                   rec.dirty = 1;
+                   /* fixme: should we verify that the record is
+                    * in the hintlist? - This case here should anyway
+                    * never occur */
+               }
+           }
+           else {
+               log_error(_("sig record %lu[%d] points to wrong record.\n"),
+                           rec.r.sig.sig[i].lid, i );
+               die_invalid_db();
+           }
+       }
+       if( found_delrec && delrec.recnum ) {
+           delrec = rec;
+           found_delrec = 0; /* we only want the first one */
+       }
+       if( rec.dirty ) {
+           write_record( &rec );
+           rec.dirty = 0;
+       }
     }
 
-    return 0;
+    if( found_sig )
+       return;
+
+    /* at this point, we have verified, that the signature is not in
+     * our list of signatures. Add a new record with that signature
+     * and if the public key is there, check the signature. */
+
+    if( !pk_lid ) /* we have already seen that there is no pubkey */
+       rc = G10ERR_NO_PUBKEY;
+    else
+       rc = check_key_signature( keyblock, signode, NULL );
+
+    if( !rc ) { /* valid signature */
+       if( opt.verbose )
+           log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+                         (ulong)keyid[1], lid, uidhash[18],
+                          uidhash[19], (ulong)sig->keyid[1],
+                               revoke? _("Valid certificate revocation")
+                                     : _("Good certificate") );
+       newlid = pk_lid;  /* this is the pk of the signature */
+       newflag = SIGF_CHECKED | SIGF_VALID;
+       if( revoke )
+           newflag |= SIGF_REVOKED;
+    }
+    else if( rc == G10ERR_NO_PUBKEY ) {
+       if( opt.verbose > 1 )
+           log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
+                    (ulong)keyid[1], lid, uidhash[18],
+                     uidhash[19], (ulong)sig->keyid[1], g10_errstr(rc) );
+       newlid = create_shadow_dir( sig, lid );
+       newflag = SIGF_NOPUBKEY;
+       if( revoke )
+           newflag |= SIGF_REVOKED;
+    }
+    else {
+       log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
+                   (ulong)keyid[1], lid, uidhash[18], uidhash[19],
+                             (ulong)sig->keyid[1],
+               revoke? _("Invalid certificate revocation")
+                     : _("Invalid certificate"),
+                                           g10_errstr(rc));
+       newlid = create_shadow_dir( sig, lid );
+       newflag = SIGF_CHECKED;
+       if( revoke )
+           newflag |= SIGF_REVOKED;
+    }
+
+    if( delrec.recnum ) { /* we can reuse a deleted/unused slot */
+       delrec.r.sig.sig[delrecidx].lid = newlid;
+       delrec.r.sig.sig[delrecidx].flag= newflag;
+       write_record( &delrec );
+    }
+    else { /* must insert a new sig record */
+       TRUSTREC tmp;
+
+       memset( &tmp, 0, sizeof tmp );
+       tmp.recnum = tdbio_new_recnum();
+       tmp.rectype = RECTYPE_SIG;
+       tmp.r.sig.lid = lid;
+       tmp.r.sig.next = urec->r.uid.siglist;
+       tmp.r.sig.sig[0].lid = newlid;
+       tmp.r.sig.sig[0].flag= newflag;
+       write_record( &tmp );
+       urec->r.uid.siglist = tmp.recnum;
+       urec->dirty = 1;
+    }
 }
 
 
+/****************
+ * Update all the info from the public keyblock.
+ * The key must already exist in the keydb.
+ * This function is responsible for checking the signatures in cases
+ * where the public key is already available.  If we do not have the public
+ * key, the check is done by some special code in insert_trust_record().
+ */
 int
-verify_private_data()
+update_trust_record( KBNODE keyblock, int recheck, int *modified )
 {
+    PKT_public_key *primary_pk;
+    KBNODE node;
+    TRUSTREC drec;
+    TRUSTREC krec;
+    TRUSTREC urec;
+    TRUSTREC prec;
+    TRUSTREC helprec;
     int rc = 0;
-    char *sigfile = make_filename(opt.homedir, "gnupg.sig", NULL );
+    u32 keyid[2]; /* keyid of primary key */
+    ulong recno, lastrecno;
+    RECNO_LIST recno_list = NULL; /* list of verified records */
+    /* fixme: replace recno_list by a lookup on node->recno */
 
-    if( access( sigfile, R_OK ) ) {
-       if( errno != ENOENT ) {
-           log_error("can't access %s: %s\n", sigfile, strerror(errno) );
-           rc = G10ERR_TRUSTDB;
-           goto leave;
+    if( modified )
+       *modified = 0;
+
+    node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+    primary_pk = node->pkt->pkt.public_key;
+    rc = get_dir_record( primary_pk, &drec );
+    if( rc )
+       return rc;
+    if( !primary_pk->local_id )
+       primary_pk->local_id = drec.recnum;
+
+    keyid_from_pk( primary_pk, keyid );
+
+    /* fixme: check that the keyblock has a valid structure */
+
+    rc = tdbio_begin_transaction();
+    if( rc )
+       return rc;
+
+    /* update the keys */
+    for( node=keyblock; node; node = node->next ) {
+       if( node->pkt->pkttype == PKT_PUBLIC_KEY
+           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+           upd_key_record( keyblock, node, keyid,
+                           &drec, &recno_list, recheck );
+    }
+    /* update the user IDs */
+    for( node=keyblock; node; node = node->next ) {
+       if( node->pkt->pkttype == PKT_USER_ID )
+           upd_uid_record( keyblock, node, keyid,
+                           &drec, &recno_list, recheck );
+    }
+
+    /* delete keyrecords from the trustdb which are not anymore used */
+    /* should we really do this, or is it better to keep them and */
+    /* mark as unused? */
+    /* And set the revocation flag into the dir record */
+    drec.r.dir.dirflags &= ~DIRF_REVOKED;
+    lastrecno = 0;
+    for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
+       read_record( recno, &krec, RECTYPE_KEY );
+       if( recno == drec.r.dir.keylist ) { /* this is the primary key */
+           if( (krec.r.key.keyflags & KEYF_REVOKED) ) {
+               drec.r.dir.dirflags |= DIRF_REVOKED;
+               drec.dirty = 1;
+           }
        }
-       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;
+
+       if( !qry_recno_list( recno_list, recno, RECTYPE_KEY ) ) {
+           /* delete this one */
+           if( !lastrecno ) {
+               drec.r.dir.keylist = krec.r.key.next;
+               drec.dirty = 1;
+           }
+           else {
+               read_record( lastrecno, &helprec, RECTYPE_KEY );
+               helprec.r.key.next = krec.r.key.next;
+               write_record( &helprec );
+           }
+           delete_record( recno );
        }
+       else
+           lastrecno = recno;
+    }
+    /* delete uid records and sig and their pref records from the
+     * trustdb which are not anymore used */
+    lastrecno = 0;
+    for( recno=drec.r.dir.uidlist; recno; recno = urec.r.uid.next ) {
+       read_record( recno, &urec, RECTYPE_UID );
+       if( !qry_recno_list( recno_list, recno, RECTYPE_UID ) ) {
+           ulong r2;
+           /* delete this one */
+           if( !lastrecno ) {
+               drec.r.dir.uidlist = urec.r.uid.next;
+               drec.dirty = 1;
+           }
+           else {
+               read_record( lastrecno, &helprec, RECTYPE_UID );
+               helprec.r.uid.next = urec.r.uid.next;
+               write_record( &helprec );
+           }
+           for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) {
+               read_record( r2, &prec, RECTYPE_PREF );
+               delete_record( r2 );
+           }
+           for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) {
+               read_record( r2, &helprec, RECTYPE_SIG );
+               delete_record( r2 );
+           }
+           delete_record( recno );
+       }
+       else
+           lastrecno = recno;
     }
 
-    /* FIXME: verify this signature */
 
-  leave:
-    m_free(sigfile);
+
+    if( rc )
+       rc = tdbio_cancel_transaction();
+    else {
+       if( modified && tdbio_is_dirty() )
+           *modified = 1;
+       drec.r.dir.dirflags |= DIRF_CHECKED;
+       drec.r.dir.dirflags &= ~DIRF_VALVALID;
+       write_record( &drec );
+       rc = tdbio_end_transaction();
+    }
+    rel_recno_list( &recno_list );
     return rc;
 }
 
 
+/****************
+ * Insert a trust record into the TrustDB
+ * This function assumes that the record does not yet exist.
+ */
 int
-sign_private_data()
+insert_trust_record( PKT_public_key *pk )
 {
-    int rc;
-    char *sigfile = make_filename(opt.homedir, "gnupg.sig", NULL );
-    char *secring = make_filename(opt.homedir, "secring.gpg", NULL );
-    STRLIST list = NULL;
+    TRUSTREC dirrec;
+    TRUSTREC shadow;
+    KBNODE keyblock = NULL;
+    KBNODE node;
+    byte fingerprint[MAX_FINGERPRINT_LEN];
+    size_t fingerlen;
+    int rc = 0;
+    ulong hintlist = 0;
+
+    if( pk->local_id )
+       log_bug("pk->local_id=%lu\n", pk->local_id );
+
+    fingerprint_from_pk( pk, fingerprint, &fingerlen );
+
+    /* fixme: assert that we do not have this record.
+     * we can do this by searching for the primary keyid
+     *
+     * fixme: If there is no such key we should look whether one
+     * of the subkeys has been used to sign another key and in this case
+     * we got the key anyway.  Because a secondary key can't be used
+     * without a primary key (it is needed to bind the secondary one
+     * to the primary one which has the user ids etc.)
+     */
+
+    /* get the keyblock which has the key */
+    rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
+    if( rc ) { /* that should never happen */
+       log_error( _("insert_trust_record: keyblock not found: %s\n"),
+                                                         g10_errstr(rc) );
+       goto leave;
+    }
+
+    /* check that we used the primary key (we are little bit paranoid) */
+    {  PKT_public_key *a_pk;
+       u32 akid[2], bkid[2];
 
-    add_to_strlist( &list, db_name );
-    add_to_strlist( &list, secring );
+       node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+       a_pk = node->pkt->pkt.public_key;
 
-    rc = sign_file( list, 1, NULL, 0, NULL, sigfile);
+       /* we can't use cmp_public_keys here because some parts (expiredate)
+        * might not be set in pk <--- but why (fixme) */
+       keyid_from_pk( a_pk, akid );
+       keyid_from_pk( pk, bkid );
 
-    m_free(sigfile);
-    m_free(secring);
-    free_strlist(list);
+       if( akid[0] != bkid[0] || akid[1] != bkid[1] ) {
+           log_error(_("did not use primary key for insert_trust_record()\n"));
+           rc = G10ERR_GENERAL;
+           goto leave;
+       }
+    }
+
+    /* We have to look for a shadow dir record which must be reused
+     * as the dir record. And: check all signatures which are listed
+     * in the hintlist of the shadow dir record.
+     */
+    rc = tdbio_search_sdir( pk->keyid, pk->pubkey_algo, &shadow );
+    if( rc && rc != -1 ) {
+       log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
+       die_invalid_db();
+    }
+    memset( &dirrec, 0, sizeof dirrec );
+    dirrec.rectype = RECTYPE_DIR;
+    if( !rc ) {
+       /* hey, great: this key has already signed other keys
+        * convert this to a real directory entry */
+       hintlist = shadow.r.sdir.hintlist;
+       dirrec.recnum = shadow.recnum;
+    }
+    else {
+       dirrec.recnum = tdbio_new_recnum();
+    }
+    dirrec.r.dir.lid = dirrec.recnum;
+    write_record( &dirrec );
+
+    /* store the LID */
+    pk->local_id = dirrec.r.dir.lid;
+    for( node=keyblock; node; node = node->next ) {
+       if( node->pkt->pkttype == PKT_PUBLIC_KEY
+           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+           PKT_public_key *pk = node->pkt->pkt.public_key;
+           pk->local_id = dirrec.r.dir.lid;
+       }
+       else if( node->pkt->pkttype == PKT_SIGNATURE ) {
+           PKT_signature *sig = node->pkt->pkt.signature;
+           sig->local_id = dirrec.r.dir.lid;
+       }
+    }
+
+    /* and put all the other stuff into the keydb */
+    rc = update_trust_record( keyblock, 1, NULL );
+    if( !rc )
+       process_hintlist( hintlist, dirrec.r.dir.lid );
+
+  leave:
+    if( rc && hintlist )
+       ; /* fixme: the hintlist is not anymore anchored */
+    release_kbnode( keyblock );
+    do_sync();
     return rc;
 }
 
+
+int
+update_ownertrust( ulong lid, unsigned new_trust )
+{
+    TRUSTREC rec;
+
+    read_record( lid, &rec, RECTYPE_DIR );
+    rec.r.dir.ownertrust = new_trust;
+    write_record( &rec );
+    do_sync();
+    return 0;
+}
+
+