See ChangeLog: Thu Mar 11 16:39:46 CET 1999 Werner Koch
authorWerner Koch <wk@gnupg.org>
Thu, 11 Mar 1999 15:42:06 +0000 (15:42 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 11 Mar 1999 15:42:06 +0000 (15:42 +0000)
22 files changed:
AUTHORS
ChangeLog
NEWS
TODO
cipher/primegen.c
cipher/rndunix.c
configure.in
doc/DETAILS
doc/gpg.1pod
g10/ChangeLog
g10/Makefile.am
g10/build-packet.c
g10/g10.c
g10/import.c
g10/keyedit.c
g10/options.skel
g10/tdbdump.c [new file with mode: 0644]
g10/tdbio.c
g10/tdbio.h
g10/trustdb.c
g10/trustdb.h
scripts/distfiles

diff --git a/AUTHORS b/AUTHORS
index 01a837c..9e6cf11 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -74,12 +74,8 @@ Torbjorn Granlund <tege@noisy.tmg.se>.
 
 The keybox implementation is based on GDBM 1.7.3 by Philip A. Nelson.
 
-The file cipher/rndunix.c is based on Peter Gutmann's rndunix.c from
-cryptlib. - He promised to add the GPL as an alternative license to
-this and some other files.  We don't have a disclaimer yet, but due
-to the fact that this is only needed for non-free systems we can
-easily remove this from the distribution and put it as an extra module
-on the FTP server.
+The file cipher/rndunix.c is based on rndunix.c from cryptlib.
+Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1999.
 
 The files in debian/ are by James Troup who is the Debian maintainer
 for GnuPG.
index c71ee2a..0f61ab1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Thu Mar 11 16:39:46 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * configure.in: Remmoved the need for libtool
+
 Mon Mar  8 20:47:17 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * configure.in (DLSYM_NEEDS_UNDERSCORE): Replaced.
diff --git a/NEWS b/NEWS
index 07f84df..15d5d9e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+
+    * New command "lsign" in the keyedit menu to create non-exportable
+      signatures.  Removed --trusted-keys option.
+
+    * A bunch of changes to the key validation code.
+
+
 Noteworthy changes in version 0.9.4
 -----------------------------------
 
diff --git a/TODO b/TODO
index 2956e8a..461abb4 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,7 +1,10 @@
 
+  * Replace --trusted-keys by a local certificate (which does not get
+    exported).
+
   * Finish the EGD module.
 
-  * Implement 256 bit key Twofish.
+  * Implement 256 bit key Twofish (wait until the 2nd AES conference).
 
   * Check revocation and expire stuff. [I'm currently working on this.]
 
@@ -19,7 +22,6 @@
   * when decryptiong multiple key: print a warning only if no usable pubkey
     encrypt package was found. Extension: display a list of all recipients.
 
-  * describe the Lim-Lee algorithms
 
 Nice to have
 ------------
@@ -28,7 +30,8 @@ Nice to have
   * preferences of hash algorithms are not yet used.
   * new menu to delete signatures and list signature in menu
   * Replace the SIGUSR1 stuff by semaphores to avoid loss of a signal.
-    or use POSIX.4 realtime signals.
+    or use POSIX.4 realtime signals.  Overhaul the interface and the
+    test program.  Use it with the test suite?
   * add test cases for invalid data (scrambled armor or other random data)
   * add checking of armor trailers
   * Burn the buffers used by fopen(), or use read(2). Does this
index e948421..c7b5b75 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * ***********************************************************************
+ * The algorithm used to generate practically save primes is due to
+ * Lim and Lee as described in the CRYPTO '97 proceedings (ISBN3540633847)
+ * page 260.
  */
 
 #include <config.h>
index 145f17f..46f80ea 100644 (file)
@@ -1,11 +1,50 @@
 /****************************************************************************
  *                                                                         *
- *   BeOS Randomness-Gathering Code                                        *
- *   Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1998    *
- *   Copyright (C) 1998, 1999  Werner Koch
+ *                                                                         *
+ *   Unix Randomness-Gathering Code                                        *
+ *                                                                         *
+ *   Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1999.   *
+ *   Heavily modified for GnuPG by Werner Koch                             *
+ *                                                                         *
  *                                                                         *
  ****************************************************************************/
 
+/* This module is part of the cryptlib continuously seeded pseudorandom
+   number generator.  For usage conditions, see lib_rand.c
+
+   [Here is the notice from lib_rand.c:]
+
+   This module and the misc/rnd*.c modules represent the cryptlib
+   continuously seeded pseudorandom number generator (CSPRNG) as described in
+   my 1998 Usenix Security Symposium paper "The generation of random numbers
+   for cryptographic purposes".
+
+   The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
+   1997, 1998, 1999, all rights reserved.  Redistribution of the CSPRNG
+   modules and use in source and binary forms, with or without modification,
+   are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice
+      and this permission notice in its entirety.
+
+   2. Redistributions in binary form must reproduce the copyright notice in
+      the documentation and/or other materials provided with the distribution.
+
+   3. A copy of any bugfixes or enhancements made must be provided to the
+      author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
+      baseline version of the code.
+
+  ALTERNATIVELY, the code may be distributed under the terms of the GNU
+  General Public License, version 2 or any later version published by the
+  Free Software Foundation, in which case the provisions of the GNU GPL are
+  required INSTEAD OF the above restrictions.
+
+  Although not required under the terms of the GPL, it would still be nice if
+  you could make any changes available to the author to allow a consistent
+  code base to be maintained */
+
+
+
 /* General includes */
 
 #include <config.h>
index f5e9dfc..1e71eb7 100644 (file)
@@ -118,7 +118,7 @@ AC_PROG_CC
 AC_PROG_CPP
 AC_ISC_POSIX
 AC_PROG_INSTALL
-AM_PROG_LIBTOOL
+AC_PROG_RANLIB
 
 MPI_OPT_FLAGS=""
 if test "$GCC" = yes; then
index e204b44..81b9dce 100644 (file)
@@ -131,6 +131,9 @@ Key generation
     8) Continue with step 4 if we did not find a prime in step 7.
     9) Find a generator for that prime.
 
+    This algorithm is based on Lim and Lee's suggestion from the
+    Crypto '97 proceedings p. 260.
+
 
 
 Layout of the TrustDB
@@ -158,7 +161,9 @@ Record type 1:
            validity value from the dir record can be used.
      1 u32  locked flags
      1 u32  timestamp of trustdb creation
-     1 u32  timestamp of last modification
+     1 u32  timestamp of last modification which may affect the validity
+           of keys in the trustdb.  This value is checked against the
+           validity timestamp in the dir records.
      1 u32  timestamp of last validation
            (Used to keep track of the time, when this TrustDB was checked
             against the pubring)
@@ -183,8 +188,9 @@ Record type 2: (directory record)
      1 u32   cache record
      1 byte  ownertrust
      1 byte  dirflag
-     1 byte  validity of the key calucalted over all user ids
-    19 byte reserved
+     1 byte  maximum validity of all the user ids
+     4 byte  time of last validity check.
+    15 byte reserved
 
 
 Record type 3: (key record)
@@ -247,7 +253,7 @@ Record type 6  (sigrec)
      6 times
        1 u32  Local_id of signators dir or shadow dir record
        1 byte Flag: Bit 0 = checked: Bit 1 is valid (we have a real
-                             directory record for this)
+                            directory record for this)
                         1 = valid is set (but my be revoked)
 
 
@@ -276,7 +282,7 @@ Record type 8: (shadow directory record)
 
 
 
-Record type 9: (cache record)
+Record type 9: (cache record) NOT USED
 --------------
     Used to bind the trustDB to the concrete instance of keyblock in
     a pubring. This is used to cache information.
@@ -298,13 +304,7 @@ Record type 9:     (cache record)
      1 byte   number of marginal trusted signatures.
      1 byte   number of fully trusted signatures.
              (255 is stored for all values greater than 254)
-     1 byte   Trustlevel
-               0 = undefined (not calculated)
-               1 = unknown
-               2 = not trusted
-               3 = marginally trusted
-               4 = fully trusted
-               5 = ultimately trusted (have secret key too).
+     1 byte   Trustlevel  (see trustdb.h)
 
 
 Record Type 10 (hash table)
@@ -459,13 +459,6 @@ Other Notes
       to keep them small.
 
 
-Supported targets:
-------------------
-      powerpc-unknown-linux-gnu  (linuxppc)
-      hppa1.1-hp-hpux10.20
-
-
-
 
 
 
index 5fa703d..e0703e6 100644 (file)
@@ -75,7 +75,7 @@ B<-k> [I<username>] [I<keyring>]
     B<-kvc>   List fingerprints
     B<-kvvc>  List fingerprints and signatures
 
-B<--list-keys> [I<names>]
+B<--list-keys>  [I<names>]
     List all keys from the public keyrings, or just the
     ones given on the command line.
 
@@ -83,7 +83,7 @@ B<--list-secret-keys> [I<names>]
     List all keys from the secret keyrings, or just the
     ones given on the command line.
 
-B<--list-sigs> [I<names>]
+B<--list-sigs>  [I<names>]
     Same as B<--list-keys>, but the signatures are listed
     too.
 
@@ -117,6 +117,11 @@ B<--edit-key> I<name>
       asks whether it should be signed. This
       question is repeated for all users specified
       with B<-u>.
+    B<lsign>
+      Same as B<sign> but the signature is marked as
+      non-exportbale and will therefore never be used
+      by others.  This may be used to make keys valid
+      only in the local environment.
     B<trust>
       Change the owner trust value. This updates the
       trust-db immediately and no save is required.
@@ -129,7 +134,7 @@ B<--edit-key> I<name>
     B<delkey>
        Remove a subkey.
     B<expire>
-       Change the key expiration time. If a key is
+       Change the key expiration time.  If a key is
        selected, the time of this key will be changed.
        With no selection the key expiration of the
        primary key is changed.
@@ -200,7 +205,7 @@ B<--export-secret-keys> [I<names>]
     This is normally not very useful.
 
 B<--import>, B<--fast-import>
-    Import/merge keys. The fast version does not build
+    Import/merge keys.  The fast version does not build
     the trustdb; this can be done at any time with the
     command B<--update-trustdb>.
 
@@ -217,7 +222,7 @@ B<--import-ownertrust> [I<filename>]
 
 Long options can be put in an options file (default F<~/.gnupg/options>).
 Do not write the 2 dashes, but simply the name of the option and any
-required arguments.    Lines with a hash as the first non-white-space
+required arguments.     Lines with a hash as the first non-white-space
 character are ignored. Commands may be put in this file too, but that
 does not make sense.
 
@@ -240,20 +245,7 @@ B<--default-key>  I<name>
     is not used the default user-id is the first user-id
     from the secret keyring.
 
-B<--trusted-key>  I<keyid>
-    Assume that the key with the I<keyid> (which must be
-    a full (8 byte) keyid) is as trustworthy as one of
-    your own secret keys.  This may be used to make keys
-    valid which are not directly certified by you but
-    by a CA you trust. The advantage of this option is
-    that it shortens the path of certification.
-
-    You may also use this option to skip the verification
-    of your own secret keys which is normally done every
-    time GnuPG starts up by using the I<keyid> of
-    your key.
-
-B<-r>  I<name>, B<--recipient> I<name>
+B<-r>  I<name>, B<--recipient>  I<name>
     Encrypt for user id I<name>.  If this option is not
     specified, GnuPG asks for the user id.
 
@@ -523,11 +515,11 @@ a signature was bad, and other error codes for fatal errors.
 
 =head1 EXAMPLES
 
-  -se -r Bob [file]         sign and encrypt for user Bob
-  -sat [file]               make a clear text signature
-  -sb  [file]               make a detached signature
-  -k   [userid]             show keys
-  -kc  [userid]             show fingerprint
+  -se -r Bob [file]          sign and encrypt for user Bob
+  -sat [file]                make a clear text signature
+  -sb  [file]                make a detached signature
+  -k   [userid]              show keys
+  -kc  [userid]              show fingerprint
 
 =head1 ENVIRONMENT
 
@@ -545,14 +537,14 @@ F<~/.gnupg/pubring.gpg.lock> and the lock file
 F<~/.gnupg/trustdb.gpg>      The trust database
 F<~/.gnupg/trustdb.gpg.lock> and the lock file
 
-F<~/.gnupg/options>        May contain options
+F<~/.gnupg/options>         May contain options
 F</usr[/local]/share/gnupg/options.skel> Skeleton file
 
 F</usr[/local]/lib/gnupg/>  Default location for extensions
 
 =head1 SEE ALSO
 
-gpg(1) gpgm(1)
+gpg(1)  gpgm(1)
 
 
 =head1 WARNINGS
index f76baf9..a4841c4 100644 (file)
@@ -1,3 +1,31 @@
+Thu Mar 11 16:39:46 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * tdbdump.c: New
+
+       * trustdb.c (walk_sigrecs,do_list_sigs,list_sigs,
+       list_records,list_trustdb,export_ownertrust,import_ownertrust): Moved
+       to tdbdump.c
+       (init_trustdb): renamed to setup_trustdb.  Changed all callers.
+       (do_init_trustdb): renamed to init_trustdb().
+       * trustdb.c (die_invalid_db): replaced by tdbio_invalid.
+       * tdbio.c (tdbio_invalid): New.
+
+       * import.c (delete_inv_parts): Skip non exportable signatures.
+       * keyedit.c (sign_uid_mk_attrib): New.
+       (sign_uids): Add the local argument.
+       (keyedit_menu): New "lsign" command.
+       * trustdb.c (register_trusted_key): Removed this and all related stuff.
+       * g10.c (oTrustedKey): Removed option.
+
+       * tdbio.h (dir.valcheck): New trustdb field.
+       * tdbio.c: Add support for this field
+       (tdbio_read_modify_stamp): New.
+       (tdbio_write_modify_stamp): New.
+       * trustdb.c (do_check): Check against this field. Removed cache update.
+       (verify_key): Add cache update.
+       (upd_uid_record): Some functional changes.
+       (upd_cert_record): Ditto
+
 Wed Mar 10 11:26:18 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * keylist.c (list_keyblock): Fixed segv in uid. Print 'u' as
index c062d77..cf0286d 100644 (file)
@@ -33,6 +33,7 @@ common_source =  \
              keyid.c           \
              trustdb.c         \
              trustdb.h         \
+             tdbdump.c         \
              tdbio.c           \
              tdbio.h           \
              hkp.h             \
index 85c73b0..810bd0d 100644 (file)
@@ -549,7 +549,7 @@ find_subpkt( byte *buffer, sigsubpkttype_t reqtype,
 
 /****************
  * Create or update a signature subpacket for SIG of TYPE.
- * This functions know, where to put the data (hashed or unhashed).
+ * This functions knows where to put the data (hashed or unhashed).
  * The function may move data from the unhased part to the hashed one.
  * Note: All pointers into sig->[un]hashed are not valid after a call
  * to this function.  The data to but into the subpaket should be
index c86961d..06d660e 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
 #include "main.h"
 #include "options.h"
 #include "keydb.h"
+#include "trustdb.h"
 #include "mpi.h"
 #include "cipher.h"
 #include "filter.h"
-#include "trustdb.h"
 #include "ttyio.h"
 #include "i18n.h"
 #include "status.h"
@@ -111,7 +111,6 @@ enum cmd_and_opt_values { aNull = 0,
     oKeyring,
     oSecretKeyring,
     oDefaultKey,
-    oTrustedKey,
     oOptions,
     oDebug,
     oDebugAll,
@@ -250,7 +249,6 @@ static ARGPARSE_OPTS opts[] = {
     { oCompletesNeeded, "completes-needed", 1, N_("(default is 1)")},
     { oMarginalsNeeded, "marginals-needed", 1, N_("(default is 3)")},
     { oMaxCertDepth,   "max-cert-depth", 1, "@" },
-    { oTrustedKey, "trusted-key", 2, N_("|KEYID|ulimately trust this key")},
     { oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")},
     { oRFC1991, "rfc1991",   0, N_("emulate the mode described in RFC1991")},
     { oS2KMode, "s2k-mode",  1, N_("|N|use passphrase mode N")},
@@ -730,7 +728,6 @@ main( int argc, char **argv )
          case oMaxCertDepth: opt.max_cert_depth = pargs.r.ret_int; break;
          case oTrustDBName: trustdb_name = pargs.r.ret_str; break;
          case oDefaultKey: opt.def_secret_key = pargs.r.ret_str; break;
-         case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
          case oNoOptions: break; /* no-options */
          case oHomedir: opt.homedir = pargs.r.ret_str; break;
          case oNoBatch: opt.batch = 0; break;
@@ -938,11 +935,11 @@ main( int argc, char **argv )
       case aListSecretKeys:
       case aCheckKeys:
        if( opt.with_colons ) /* need this to list the trust */
-           rc = init_trustdb(1, trustdb_name );
+           rc = setup_trustdb(1, trustdb_name );
        break;
-      case aExportOwnerTrust: rc = init_trustdb( 0, trustdb_name ); break;
-      case aListTrustDB: rc = init_trustdb( argc? 1:0, trustdb_name ); break;
-      default: rc = init_trustdb(1, trustdb_name ); break;
+      case aExportOwnerTrust: rc = setup_trustdb( 0, trustdb_name ); break;
+      case aListTrustDB: rc = setup_trustdb( argc? 1:0, trustdb_name ); break;
+      default: rc = setup_trustdb(1, trustdb_name ); break;
     }
     if( rc )
        log_error(_("failed to initialize the TrustDB: %s\n"), g10_errstr(rc));
index 640c234..920aafb 100644 (file)
@@ -1,5 +1,5 @@
 /* import.c
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -750,6 +750,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
 {
     KBNODE node;
     int nvalid=0, uid_seen=0;
+    const char *p;
 
     for(node=keyblock->next; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_USER_ID ) {
@@ -793,6 +794,16 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
                 && node->pkt->pkt.signature->pubkey_algo != PUBKEY_ALGO_RSA )
            delete_kbnode( node ); /* build_packet() can't handle this */
        else if( node->pkt->pkttype == PKT_SIGNATURE
+                && (p = parse_sig_subpkt2( node->pkt->pkt.signature,
+                                           SIGSUBPKT_EXPORTABLE, NULL ))
+                && !*p ) {
+           log_info_f(fname, _("key %08lX: non exportable signature "
+                                   "(class %02x) - skipped\n"),
+                                   (ulong)keyid[1],
+                                    node->pkt->pkt.signature->sig_class );
+           delete_kbnode( node );
+       }
+       else if( node->pkt->pkttype == PKT_SIGNATURE
                 && node->pkt->pkt.signature->sig_class == 0x20 )  {
            if( uid_seen ) {
                log_error_f(fname, _("key %08lX: revocation certificate "
index f818b35..ad53c37 100644 (file)
@@ -69,6 +69,13 @@ static int count_selected_keys( KBNODE keyblock );
 #define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
 
 
+struct sign_uid_attrib {
+    int non_exportable;
+};
+
+
+
+
 static int
 get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
 {
@@ -200,15 +207,31 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
 }
 
 
+
+
+int
+sign_uid_mk_attrib( PKT_signature *sig, void *opaque )
+{
+    struct sign_uid_attrib *attrib = opaque;
+    byte buf[8];
+
+    if( attrib->non_exportable ) {
+       buf[0] = 0; /* not exportable */
+       build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
+    }
+
+    return 0;
+}
+
+
+
 /****************
  * Loop over all locusr and and sign the uids after asking.
  * If no user id is marked, all user ids will be signed;
  * if some user_ids are marked those will be signed.
- *
- * fixme: Add support for our proposed sign-all scheme
  */
 static int
-sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
+sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
 {
     int rc = 0;
     SK_LIST sk_list = NULL;
@@ -279,6 +302,10 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
        m_free(p); p = NULL;
        tty_printf("\"\n\n");
 
+       if( local )
+           tty_printf(
+                 _("The signature will be marked as non-exportable.\n\n"));
+
        if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
            continue;;
        /* now we can sign the user ids */
@@ -291,14 +318,19 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
                     && (node->flag & NODFLG_MARK_A) ) {
                PACKET *pkt;
                PKT_signature *sig;
+               struct sign_uid_attrib attrib;
 
                assert( primary_pk );
+               memset( &attrib, 0, sizeof attrib );
+               attrib.non_exportable = local;
                node->flag &= ~NODFLG_MARK_A;
                rc = make_keysig_packet( &sig, primary_pk,
                                               node->pkt->pkt.user_id,
                                               NULL,
                                               sk,
-                                              0x10, 0, NULL, NULL );
+                                              0x10, 0,
+                                              sign_uid_mk_attrib,
+                                              &attrib );
                if( rc ) {
                    log_error(_("signing failed: %s\n"), g10_errstr(rc));
                    goto leave;
@@ -479,6 +511,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands )
 {
     enum cmdids { cmdNONE = 0,
           cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
+          cmdLSIGN,
           cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
           cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
           cmdNOP };
@@ -501,6 +534,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands )
        { N_("c")       , cmdCHECK  , 0, NULL },
        { N_("sign")    , cmdSIGN   , 0, N_("sign the key") },
        { N_("s")       , cmdSIGN   , 0, NULL },
+       { N_("lsign")   , cmdLSIGN  , 0, N_("sign the key locally") },
        { N_("debug")   , cmdDEBUG  , 0, NULL },
        { N_("adduid")  , cmdADDUID , 1, N_("add a user id") },
        { N_("deluid")  , cmdDELUID , 0, N_("delete user id") },
@@ -696,6 +730,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands )
            break;
 
          case cmdSIGN: /* sign (only the public key) */
+         case cmdLSIGN: /* sign (only the public key) */
            if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
                if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
                                           _("Really sign all user ids? ")) ) {
@@ -703,7 +738,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands )
                    break;
                }
            }
-           sign_uids( keyblock, locusr, &modified );
+           sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN );
            break;
 
          case cmdDEBUG:
index 3e6777b..e95170b 100644 (file)
@@ -52,9 +52,11 @@ escape-from-lines
 # every time it is needed - normally this is not needed.
 lock-once
 
-# If you are not running one of the free operation systems
-# you probably have to uncomment the next line:
+# If you have configured GnuPG without a random gatherer,
+# you have to uncomment one of the following lines.
+#load-extension rndlinux
 #load-extension rndunix
+#load-extension rndegd
 
 
 # GnuPG can import a key from a HKP keyerver if one is missing
diff --git a/g10/tdbdump.c b/g10/tdbdump.c
new file mode 100644 (file)
index 0000000..f2b4ca9
--- /dev/null
@@ -0,0 +1,522 @@
+/* tdbdump.c
+ *     Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "errors.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "memory.h"
+#include "util.h"
+#include "trustdb.h"
+#include "options.h"
+#include "packet.h"
+#include "main.h"
+#include "i18n.h"
+#include "tdbio.h"
+
+
+#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
+                     (a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
+
+/****************
+ * Read a record but die if it does not exist
+ * fixme: duplicate: remove it
+ */
+static void
+read_record( ulong recno, TRUSTREC *rec, int rectype )
+{
+    int rc = tdbio_read_record( recno, rec, rectype );
+    if( !rc )
+       return;
+    log_error(_("trust record %lu, req type %d: read failed: %s\n"),
+                                   recno, rectype,  g10_errstr(rc) );
+    tdbio_invalid();
+}
+
+/****************
+ * Wirte a record but die on error
+ */
+static void
+write_record( TRUSTREC *rec )
+{
+    int rc = tdbio_write_record( rec );
+    if( !rc )
+       return;
+    log_error(_("trust record %lu, type %d: write failed: %s\n"),
+                           rec->recnum, rec->rectype, g10_errstr(rc) );
+    tdbio_invalid();
+}
+
+
+/****************
+ * sync the db
+ */
+static void
+do_sync(void)
+{
+    int rc = tdbio_sync();
+    if( !rc )
+       return;
+    log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
+    g10_exit(2);
+}
+
+
+static int
+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;
+}
+
+
+
+/****************
+ * Walk through the signatures of a public key.
+ * The caller must provide a context structure, with all fields set
+ * to zero, but the local_id field set to the requested key;
+ * This function does not change this field.  On return the context
+ * is filled with the local-id of the signature and the signature flag.
+ * No fields should be changed (clearing all fields and setting
+ * pubkeyid is okay to continue with an other pubkey)
+ * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
+ * FIXME: Do we really need this large and complicated function?
+ */
+static int
+walk_sigrecs( SIGREC_CONTEXT *c )
+{
+    TRUSTREC *r;
+    ulong rnum;
+
+    if( c->ctl.eof )
+       return -1;
+    r = &c->ctl.rec;
+    if( !c->ctl.init_done ) {
+       c->ctl.init_done = 1;
+       read_record( c->lid, r, 0 );
+       if( r->rectype != RECTYPE_DIR ) {
+           c->ctl.eof = 1;
+           return -1;  /* return eof */
+       }
+       c->ctl.nextuid = r->r.dir.uidlist;
+       /* force a read */
+       c->ctl.index = SIGS_PER_RECORD;
+       r->r.sig.next = 0;
+    }
+
+    /* need a loop to skip over deleted sigs */
+    do {
+       if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
+           rnum = r->r.sig.next;
+           if( !rnum && c->ctl.nextuid ) { /* read next uid record */
+               read_record( c->ctl.nextuid, r, RECTYPE_UID );
+               c->ctl.nextuid = r->r.uid.next;
+               rnum = r->r.uid.siglist;
+           }
+           if( !rnum ) {
+               c->ctl.eof = 1;
+               return -1;  /* return eof */
+           }
+           read_record( rnum, r, RECTYPE_SIG );
+           if( r->r.sig.lid != c->lid ) {
+               log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
+               c->ctl.eof = 1;
+               tdbio_invalid();
+           }
+           c->ctl.index = 0;
+       }
+    } while( !r->r.sig.sig[c->ctl.index++].lid );
+
+    c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
+    c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
+    return 0;
+}
+
+
+#if 0
+static int
+do_list_sigs( ulong root, ulong pk_lid, int depth,
+             LOCAL_ID_TABLE lids, unsigned *lineno )
+{
+    SIGREC_CONTEXT sx;
+    int rc;
+    u32 keyid[2];
+
+    memset( &sx, 0, sizeof sx );
+    sx.lid = pk_lid;
+    for(;;) {
+       rc = walk_sigrecs( &sx ); /* should we replace it and use */
+       if( rc )
+           break;
+       rc = keyid_from_lid( sx.sig_lid, keyid );
+       if( rc ) {
+           printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
+           print_sigflags( stdout, sx.sig_flag );
+           putchar('\n');
+           ++*lineno;
+       }
+       else {
+           printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
+                             (ulong)keyid[1], sx.sig_lid );
+           print_sigflags( stdout, sx.sig_flag );
+           putchar(' ');
+           /* check whether we already checked this pk_lid */
+           if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
+               print_user_id("[ultimately trusted]", keyid);
+               ++*lineno;
+           }
+           else if( sx.sig_lid == pk_lid ) {
+               printf("[self-signature]\n");
+               ++*lineno;
+           }
+           else if( sx.sig_lid == root ) {
+               printf("[closed]\n");
+               ++*lineno;
+           }
+           else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
+               unsigned refline;
+               qry_lid_table_flag( lids, sx.sig_lid, &refline );
+               printf("[see line %u]\n", refline);
+               ++*lineno;
+           }
+           else if( depth+1 >= MAX_LIST_SIGS_DEPTH  ) {
+               print_user_id( "[too deeply nested]", keyid );
+               ++*lineno;
+           }
+           else {
+               print_user_id( "", keyid );
+               ++*lineno;
+               rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
+               if( rc )
+                   break;
+           }
+       }
+    }
+    return rc==-1? 0 : rc;
+}
+#endif
+/****************
+ * List all signatures of a public key
+ */
+static int
+list_sigs( ulong pubkey_id )
+{
+    int rc=0;
+  #if 0
+    u32 keyid[2];
+    LOCAL_ID_TABLE lids;
+    unsigned lineno = 1;
+
+    rc = keyid_from_lid( pubkey_id, keyid );
+    if( rc )
+       return rc;
+    printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
+    print_user_id("", keyid);
+    printf("----------------------\n");
+
+    lids = new_lid_table();
+    rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
+    putchar('\n');
+    release_lid_table(lids);
+  #endif
+    return rc;
+}
+
+/****************
+ * List all records of a public key
+ */
+static int
+list_records( ulong lid )
+{
+    int rc;
+    TRUSTREC dr, ur, rec;
+    ulong recno;
+
+    rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
+    if( rc ) {
+       log_error(_("lid %lu: read dir record failed: %s\n"),
+                                               lid, g10_errstr(rc));
+       return rc;
+    }
+    tdbio_dump_record( &dr, stdout );
+
+    for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
+       rc = tdbio_read_record( recno, &rec, 0 );
+       if( rc ) {
+           log_error(_("lid %lu: read key record failed: %s\n"),
+                                               lid, g10_errstr(rc));
+           return rc;
+       }
+       tdbio_dump_record( &rec, stdout );
+    }
+
+    for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
+       rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
+       if( rc ) {
+           log_error(_("lid %lu: read uid record failed: %s\n"),
+                                               lid, g10_errstr(rc));
+           return rc;
+       }
+       tdbio_dump_record( &ur, stdout );
+       /* preference records */
+       for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
+           rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
+           if( rc ) {
+               log_error(_("lid %lu: read pref record failed: %s\n"),
+                                                   lid, g10_errstr(rc));
+               return rc;
+           }
+           tdbio_dump_record( &rec, stdout );
+       }
+       /* sig records */
+       for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
+           rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
+           if( rc ) {
+               log_error(_("lid %lu: read sig record failed: %s\n"),
+                                                   lid, g10_errstr(rc));
+               return rc;
+           }
+           tdbio_dump_record( &rec, stdout );
+       }
+    }
+
+    /* add cache record dump here */
+
+
+
+    return rc;
+}
+
+
+/****************
+ * Dump the complte trustdb or only the entries of one key.
+ */
+void
+list_trustdb( const char *username )
+{
+    TRUSTREC rec;
+
+    init_trustdb();
+
+    if( username && *username == '#' ) {
+       int rc;
+       ulong lid = atoi(username+1);
+
+       if( (rc = list_records( lid)) )
+           log_error(_("user '%s' read problem: %s\n"),
+                                           username, g10_errstr(rc));
+       else if( (rc = list_sigs( lid )) )
+           log_error(_("user '%s' list problem: %s\n"),
+                                           username, g10_errstr(rc));
+    }
+    else if( username ) {
+       PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+       int rc;
+
+       if( (rc = get_pubkey_byname( 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_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", tdbio_get_dbname() );
+       for(i=9+strlen(tdbio_get_dbname()); i > 0; i-- )
+           putchar('-');
+       putchar('\n');
+       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
+export_ownertrust()
+{
+    TRUSTREC rec;
+    TRUSTREC rec2;
+    ulong recnum;
+    int i;
+    byte *p;
+    int rc;
+
+    init_trustdb();
+    printf(_("# List of assigned trustvalues, created %s\n"
+            "# (Use \"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 );
+       }
+    }
+}
+
+
+void
+import_ownertrust( const char *fname )
+{
+    FILE *fp;
+    int is_stdin=0;
+    char line[256];
+    char *p;
+    size_t n, fprlen;
+    unsigned otrust;
+
+    init_trustdb();
+    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;
+    }
+
+    while( fgets( line, DIM(line)-1, fp ) ) {
+       TRUSTREC rec;
+       int rc;
+
+       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 */
+       }
+       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) );
+               }
+           }
+       }
+       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();
+}
+
index 3ba238c..22592ae 100644 (file)
@@ -82,7 +82,6 @@ static int is_locked;
 static int  db_fd = -1;
 static int in_transaction;
 
-
 static void open_db(void);
 
 \f
@@ -317,6 +316,7 @@ tdbio_sync()
        if( !release_dotlock( lockhandle ) )
            is_locked = 0;
     }
+
     return 0;
 }
 
@@ -609,6 +609,55 @@ tdbio_db_matches_options()
 
 
 /****************
+ * Return the modifiy stamp.
+ * if modify_down is true, the modify_down stamp will be
+ * returned, otherwise the modify_up stamp.
+ */
+ulong
+tdbio_read_modify_stamp( int modify_down )
+{
+    TRUSTREC vr;
+    int rc;
+    ulong mod;
+
+    rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
+    if( rc )
+       log_fatal( _("%s: error reading version record: %s\n"),
+                                                   db_name, g10_errstr(rc) );
+
+    mod = modify_down? vr.r.ver.mod_down : vr.r.ver.mod_up;
+
+    /* Always return at least 1 to make comparison easier;
+     * this is still far back in history (before Led Zeppelin III :-) */
+    return mod ? mod : 1;
+}
+
+void
+tdbio_write_modify_stamp( int down, int up )
+{
+    TRUSTREC vr;
+    int rc;
+    ulong stamp;
+
+    rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
+    if( rc )
+       log_fatal( _("%s: error reading version record: %s\n"),
+                                      db_name, g10_errstr(rc) );
+
+    stamp = make_timestamp();
+    if( down )
+       vr.r.ver.mod_down = stamp;
+    if( up )
+       vr.r.ver.mod_up = stamp;
+
+    rc = tdbio_write_record( &vr );
+    if( !rc )
+       log_fatal( _("%s: error writing version record: %s\n"),
+                                      db_name, g10_errstr(rc) );
+}
+
+
+/****************
  * Return the record number of the keyhash tbl or create a new one.
  */
 static ulong
@@ -936,12 +985,14 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp  )
       case 0: fprintf(fp, "blank\n");
        break;
       case RECTYPE_VER: fprintf(fp,
-           "version, kd=%lu, sd=%lu, free=%lu, m/c/d=%d/%d/%d\n",
+           "version, kd=%lu, sd=%lu, free=%lu, m/c/d=%d/%d/%d down=%s",
            rec->r.ver.keyhashtbl, rec->r.ver.sdirhashtbl,
                                   rec->r.ver.firstfree,
                                   rec->r.ver.marginals,
                                   rec->r.ver.completes,
-                                  rec->r.ver.cert_depth );
+                                  rec->r.ver.cert_depth,
+                                  strtimestamp(rec->r.ver.mod_down) );
+           fprintf(fp, ", up=%s\n", strtimestamp(rec->r.ver.mod_up) );
        break;
       case RECTYPE_FREE: fprintf(fp, "free, next=%lu\n", rec->r.free.next );
        break;
@@ -951,8 +1002,9 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp  )
                    rec->r.dir.keylist,
                    rec->r.dir.uidlist,
                    rec->r.dir.ownertrust );
-       if( rec->r.dir.dirflags & DIRF_VALVALID )
-           fprintf( fp, ", v=%02x", rec->r.dir.validity );
+       if( rec->r.dir.valcheck )
+           fprintf( fp, ", v=%02x/%s", rec->r.dir.validity,
+                                       strtimestamp(rec->r.dir.valcheck) );
        if( rec->r.dir.dirflags & DIRF_CHECKED ) {
            if( rec->r.dir.dirflags & DIRF_VALID )
                fputs(", valid", fp );
@@ -987,8 +1039,7 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp  )
                    rec->r.uid.prefrec,
                    rec->r.uid.siglist,
                    rec->r.uid.namehash[18], rec->r.uid.namehash[19]);
-       if( rec->r.uid.uidflags & UIDF_VALVALID )
-           fprintf( fp, ", v=%02x", rec->r.uid.validity );
+       fprintf( fp, ", v=%02x", rec->r.uid.validity );
        if( rec->r.uid.uidflags & UIDF_CHECKED ) {
            if( rec->r.uid.uidflags & UIDF_VALID )
                fputs(", valid", fp );
@@ -1113,8 +1164,8 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
        rec->r.ver.cert_depth = *p++;
        p += 4; /* lock flags */
        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.mod_down = buftoulong(p); p += 4;
+       rec->r.ver.mod_up   = buftoulong(p); p += 4;
        rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
        rec->r.ver.firstfree =buftoulong(p); p += 4;
        rec->r.ver.sdirhashtbl =buftoulong(p); p += 4;
@@ -1140,6 +1191,7 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
        rec->r.dir.ownertrust = *p++;
        rec->r.dir.dirflags   = *p++;
        rec->r.dir.validity   = *p++;
+       rec->r.dir.valcheck   = buftoulong(p); p += 4;
        switch( rec->r.dir.validity ) {
          case 0:
          case TRUST_UNDEFINED:
@@ -1270,8 +1322,8 @@ tdbio_write_record( TRUSTREC *rec )
        *p++ = rec->r.ver.cert_depth;
        p += 4; /* skip lock flags */
        ulongtobuf(p, rec->r.ver.created); p += 4;
-       ulongtobuf(p, rec->r.ver.modified); p += 4;
-       ulongtobuf(p, rec->r.ver.validated); p += 4;
+       ulongtobuf(p, rec->r.ver.mod_down); p += 4;
+       ulongtobuf(p, rec->r.ver.mod_up); p += 4;
        ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
        ulongtobuf(p, rec->r.ver.firstfree ); p += 4;
        ulongtobuf(p, rec->r.ver.sdirhashtbl ); p += 4;
@@ -1289,6 +1341,7 @@ tdbio_write_record( TRUSTREC *rec )
        *p++ = rec->r.dir.ownertrust;
        *p++ = rec->r.dir.dirflags;
        *p++ = rec->r.dir.validity;
+       ulongtobuf(p, rec->r.dir.valcheck); p += 4;
        assert( rec->r.dir.lid == recnum );
        break;
 
@@ -1566,3 +1619,12 @@ tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec )
 }
 
 
+void
+tdbio_invalid(void)
+{
+    log_error(_(
+       "The trustdb is corrupted; please run \"gpgm --fix-trustdb\".\n") );
+    g10_exit(2);
+}
+
+
index 62148d3..9c97dd1 100644 (file)
@@ -52,7 +52,6 @@
                        /* one uid with a selfsignature or an revocation */
 #define DIRF_EXPIRED  4 /* the complete key has expired */
 #define DIRF_REVOKED  8 /* the complete key has been revoked */
-#define DIRF_VALVALID 16 /* The validity field is valid */
 
 #define KEYF_CHECKED  1 /* This key has been checked */
 #define KEYF_VALID    2 /* This is a valid (sub)key */
@@ -62,7 +61,6 @@
 #define UIDF_CHECKED  1  /* user id has been checked - other bits are valid */
 #define UIDF_VALID    2  /* this is a valid user id */
 #define UIDF_REVOKED  8  /* this user id has been revoked */
-#define UIDF_VALVALID 16 /* the validity field is valid */
 
 #define SIGF_CHECKED  1 /* signature has been checked - bits 0..6 are valid */
 #define SIGF_VALID    2 /* the signature is valid */
@@ -83,8 +81,8 @@ struct trust_record {
            byte  completes;
            byte  cert_depth;
            ulong created;   /* timestamp of trustdb creation  */
-           ulong modified;  /* timestamp of last modification */
-           ulong validated; /* timestamp of last validation   */
+           ulong mod_down;  /* timestamp of last modification downward */
+           ulong mod_up;    /* timestamp of last modification upward */
            ulong keyhashtbl;
            ulong firstfree;
            ulong sdirhashtbl;
@@ -99,7 +97,8 @@ struct trust_record {
            ulong cacherec; /* the cache record */
            byte ownertrust;
            byte dirflags;
-           byte validity; /* calculated trustlevel over all uids */
+           byte validity;  /* calculated trustlevel over all uids */
+           ulong valcheck; /* timestamp of last validation check */
        } dir;
        struct {            /* primary public key record */
            ulong lid;
@@ -176,6 +175,8 @@ void tdbio_dump_record( TRUSTREC *rec, FILE *fp );
 int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
 int tdbio_write_record( TRUSTREC *rec );
 int tdbio_db_matches_options(void);
+ulong tdbio_read_modify_stamp( int modify_down );
+void tdbio_write_modify_stamp( int down, int up );
 int tdbio_is_dirty(void);
 int tdbio_sync(void);
 int tdbio_begin_transaction(void);
@@ -188,5 +189,6 @@ int tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
                                        int pubkey_algo, TRUSTREC *rec );
 int tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec );
 
+void tdbio_invalid(void);
 
 #endif /*G10_TDBIO_H*/
index 2a37641..557b4cc 100644 (file)
@@ -109,18 +109,15 @@ static int alloced_tns;
 static int max_alloced_tns;
 
 
-static int walk_sigrecs( SIGREC_CONTEXT *c );
 
 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 int propagate_validity( TN node );
+static void propagate_validity( TN node );
 
 static void print_user_id( const char *text, u32 *keyid );
-static int list_sigs( ulong pubkey_id );
 static int do_check( TRUSTREC *drec, unsigned *trustlevel, const char *nhash);
 static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
 
@@ -129,8 +126,6 @@ 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 revoked );
 
-static struct keyid_list *trusted_key_list;
-
 /* 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;
@@ -144,27 +139,12 @@ static struct {
     int level;
     char *dbname;
 } trustdb_args;
-#define INIT_TRUSTDB() do { if( !trustdb_args.init ) \
-                               do_init_trustdb();   \
-                         } while(0)
-static void do_init_trustdb(void);
-
-#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
-                     (a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
-
 
 \f
 /**********************************************
  ***********  record read write  **************
  **********************************************/
 
-static void
-die_invalid_db(void)
-{
-    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
@@ -177,7 +157,7 @@ read_record( ulong recno, TRUSTREC *rec, int rectype )
        return;
     log_error(_("trust record %lu, req type %d: read failed: %s\n"),
                                    recno, rectype,  g10_errstr(rc) );
-    die_invalid_db();
+    tdbio_invalid();
 }
 
 
@@ -192,7 +172,7 @@ write_record( TRUSTREC *rec )
        return;
     log_error(_("trust record %lu, type %d: write failed: %s\n"),
                            rec->recnum, rec->rectype, g10_errstr(rc) );
-    die_invalid_db();
+    tdbio_invalid();
 }
 
 /****************
@@ -206,7 +186,7 @@ delete_record( ulong recno )
        return;
     log_error(_("trust record %lu: delete failed: %s\n"),
                                              recno, g10_errstr(rc) );
-    die_invalid_db();
+    tdbio_invalid();
 }
 
 /****************
@@ -225,7 +205,7 @@ do_sync(void)
 
 \f
 /**********************************************
- ************* list helpers *******************
+ *****************  helpers  ******************
  **********************************************/
 
 /****************
@@ -280,6 +260,7 @@ new_lid_table(void)
     return a;
 }
 
+#if 0
 static void
 release_lid_table( LOCAL_ID_TABLE tbl )
 {
@@ -296,6 +277,7 @@ release_lid_table( LOCAL_ID_TABLE tbl )
     tbl->next = unused_lid_tables;
     unused_lid_tables = tbl;
 }
+#endif
 
 /****************
  * Add a new item to the table or return 1 if we already have this item
@@ -335,6 +317,53 @@ qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag )
 }
 
 
+static TN
+new_tn(void)
+{
+    TN t;
+
+    if( used_tns ) {
+       t = used_tns;
+       used_tns = t->next;
+       memset( t, 0, sizeof *t );
+    }
+    else
+       t = m_alloc_clear( sizeof *t );
+    if( ++alloced_tns > max_alloced_tns )
+       max_alloced_tns = alloced_tns;
+    return t;
+}
+
+
+static void
+release_tn( TN t )
+{
+    if( t ) {
+       t->next = used_tns;
+       used_tns = t;
+       alloced_tns--;
+    }
+}
+
+
+static void
+release_tn_tree( TN kr )
+{
+    TN kr2;
+
+    for( ; kr; kr = kr2 ) {
+       release_tn_tree( kr->list );
+       kr2 = kr->next;
+       release_tn( kr );
+    }
+}
+
+
+
+\f
+/**********************************************
+ ****** access by LID and other helpers *******
+ **********************************************/
 
 /****************
  * Return the keyid from the primary key identified by LID.
@@ -345,7 +374,7 @@ keyid_from_lid( ulong lid, u32 *keyid )
     TRUSTREC rec;
     int rc;
 
-    INIT_TRUSTDB();
+    init_trustdb();
     rc = tdbio_read_record( lid, &rec, 0 );
     if( rc ) {
        log_error(_("error reading dir record for LID %lu: %s\n"),
@@ -386,7 +415,7 @@ lid_from_keyblock( KBNODE keyblock )
     pk = node->pkt->pkt.public_key;
     if( !pk->local_id ) {
        TRUSTREC rec;
-       INIT_TRUSTDB();
+       init_trustdb();
 
        get_dir_record( pk, &rec );
     }
@@ -394,111 +423,63 @@ lid_from_keyblock( KBNODE keyblock )
 }
 
 
-\f
+static int
+get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
+{
+    int rc=0;
+
+    if( pk->local_id ) {
+       read_record( pk->local_id, rec, RECTYPE_DIR );
+    }
+    else { /* no local_id: scan the trustdb */
+       if( (rc=tdbio_search_dir_bypk( pk, rec )) && rc != -1 )
+           log_error(_("get_dir_record: search_record failed: %s\n"),
+                                                           g10_errstr(rc));
+    }
+    return rc;
+}
+
 /****************
- * Walk through the signatures of a public key.
- * The caller must provide a context structure, with all fields set
- * to zero, but the local_id field set to the requested key;
- * This function does not change this field.  On return the context
- * is filled with the local-id of the signature and the signature flag.
- * No fields should be changed (clearing all fields and setting
- * pubkeyid is okay to continue with an other pubkey)
- * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
+ * Get the LID of a public key.
+ * Returns: The LID of the key (note, that this may be a shadow dir)
+ *         or 0 if not available.
  */
-static int
-walk_sigrecs( SIGREC_CONTEXT *c )
+static ulong
+lid_from_keyid( u32 *keyid )
 {
-    TRUSTREC *r;
-    ulong rnum;
+    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+    TRUSTREC rec;
+    ulong lid = 0;
+    int rc;
 
-    if( c->ctl.eof )
-       return -1;
-    r = &c->ctl.rec;
-    if( !c->ctl.init_done ) {
-       c->ctl.init_done = 1;
-       read_record( c->lid, r, 0 );
-       if( r->rectype != RECTYPE_DIR ) {
-           c->ctl.eof = 1;
-           return -1;  /* return eof */
-       }
-       c->ctl.nextuid = r->r.dir.uidlist;
-       /* force a read */
-       c->ctl.index = SIGS_PER_RECORD;
-       r->r.sig.next = 0;
-    }
-
-    /* need a loop to skip over deleted sigs */
-    do {
-       if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
-           rnum = r->r.sig.next;
-           if( !rnum && c->ctl.nextuid ) { /* read next uid record */
-               read_record( c->ctl.nextuid, r, RECTYPE_UID );
-               c->ctl.nextuid = r->r.uid.next;
-               rnum = r->r.uid.siglist;
-           }
-           if( !rnum ) {
-               c->ctl.eof = 1;
-               return -1;  /* return eof */
-           }
-           read_record( rnum, r, RECTYPE_SIG );
-           if( r->r.sig.lid != c->lid ) {
-               log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
-               c->ctl.eof = 1;
-               die_invalid_db();
+    rc = get_pubkey( pk, keyid );
+    if( !rc ) {
+       if( pk->local_id )
+           lid = pk->local_id;
+       else {
+           rc = tdbio_search_dir_bypk( pk, &rec );
+           if( !rc )
+               lid = rec.recnum;
+           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 )
+                   lid = rec.recnum;
            }
-           c->ctl.index = 0;
        }
-    } while( !r->r.sig.sig[c->ctl.index++].lid );
-
-    c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
-    c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
-    return 0;
+    }
+    free_public_key( pk );
+    return lid;
 }
 
 
-
 \f
 /***********************************************
- ************* Trust  stuff  ******************
+ ************* Initialization  ****************
  ***********************************************/
 
-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.
  */
@@ -510,44 +491,6 @@ verify_own_keys(void)
     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, sk, 0 ) ) ) {
        int have_pk = 0;
@@ -561,10 +504,6 @@ verify_own_keys(void)
            log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
                                                            (ulong)keyid[1] );
 
-       for( kl = trusted_key_list; kl; kl = kl->next ) {
-           if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
-               goto skip; /* already in trusted key table */
-       }
 
        /* see whether we can access the public key of this secret key */
        memset( pk, 0, sizeof *pk );
@@ -617,15 +556,6 @@ verify_own_keys(void)
     else
        rc = 0;
 
-    /* release the trusted keyid table */
-    {  struct keyid_list *kl2;
-       for( kl = trusted_key_list; kl; kl = kl2 ) {
-           kl2 = kl->next;
-           m_free( kl );
-       }
-       trusted_key_list = NULL;
-    }
-
     enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
     free_secret_key( sk );
     free_public_key( pk );
@@ -633,6 +563,64 @@ verify_own_keys(void)
 }
 
 
+/****************
+ * Perform some checks over the trustdb
+ *  level 0: only open the db
+ *       1: used for initial program startup
+ */
+int
+setup_trustdb( int level, const char *dbname )
+{
+    /* just store the args */
+    if( trustdb_args.init )
+       return 0;
+    trustdb_args.level = level;
+    trustdb_args.dbname = dbname? m_strdup(dbname): NULL;
+    return 0;
+}
+
+void
+init_trustdb()
+{
+    int rc=0;
+    int level = trustdb_args.level;
+    const char* dbname = trustdb_args.dbname;
+
+    if( trustdb_args.init )
+       return;
+
+    trustdb_args.init = 1;
+
+    if( !ultikey_table )
+       ultikey_table = new_lid_table();
+
+    if( !level || level==1 ) {
+       rc = tdbio_set_dbname( dbname, !!level );
+       if( !rc ) {
+           if( !level )
+               return;
+
+           /* verify that our own keys are in the trustDB
+            * or move them to the trustdb. */
+           rc = verify_own_keys();
+
+           /* should we check whether there is no other ultimately trusted
+            * key in the database? */
+       }
+    }
+    else
+       BUG();
+    if( rc )
+       log_fatal("can't init trustdb: %s\n", g10_errstr(rc) );
+}
+
+
+
+
+\f
+/***********************************************
+ ************* Print helpers   ****************
+ ***********************************************/
 static void
 print_user_id( const char *text, u32 *keyid )
 {
@@ -652,2634 +640,2233 @@ print_user_id( const char *text, u32 *keyid )
 }
 
 
-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 )
+int
+trust_letter( unsigned value )
 {
-    SIGREC_CONTEXT sx;
-    int rc;
-    u32 keyid[2];
-
-    memset( &sx, 0, sizeof sx );
-    sx.lid = pk_lid;
-    for(;;) {
-       rc = walk_sigrecs( &sx ); /* should we replace it and use */
-       if( rc )
-           break;
-       rc = keyid_from_lid( sx.sig_lid, keyid );
-       if( rc ) {
-           printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
-           print_sigflags( stdout, sx.sig_flag );
-           putchar('\n');
-           ++*lineno;
-       }
-       else {
-           printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
-                             (ulong)keyid[1], sx.sig_lid );
-           print_sigflags( stdout, sx.sig_flag );
-           putchar(' ');
-           /* check whether we already checked this pk_lid */
-           if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
-               print_user_id("[ultimately trusted]", keyid);
-               ++*lineno;
-           }
-           else if( sx.sig_lid == pk_lid ) {
-               printf("[self-signature]\n");
-               ++*lineno;
-           }
-           else if( sx.sig_lid == root ) {
-               printf("[closed]\n");
-               ++*lineno;
-           }
-           else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
-               unsigned refline;
-               qry_lid_table_flag( lids, sx.sig_lid, &refline );
-               printf("[see line %u]\n", refline);
-               ++*lineno;
-           }
-           else if( depth+1 >= MAX_LIST_SIGS_DEPTH  ) {
-               print_user_id( "[too deeply nested]", keyid );
-               ++*lineno;
-           }
-           else {
-               print_user_id( "", keyid );
-               ++*lineno;
-               rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
-               if( rc )
-                   break;
-           }
-       }
+    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 ;
     }
-    return rc==-1? 0 : rc;
 }
 
-/****************
- * List all signatures of a public key
- */
-static int
-list_sigs( ulong pubkey_id )
+
+#if 0
+static void
+print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
 {
-    int rc;
+    int rc, c, i;
     u32 keyid[2];
-    LOCAL_ID_TABLE lids;
-    unsigned lineno = 1;
-
-    rc = keyid_from_lid( pubkey_id, keyid );
-    if( rc )
-       return rc;
-    printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
-    print_user_id("", keyid);
-    printf("----------------------\n");
-
-    lids = new_lid_table();
-    rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
-    putchar('\n');
-    release_lid_table(lids);
-    return rc;
-}
+    char *p;
+    size_t n;
 
-/****************
- * List all records of a public key
- */
-static int
-list_records( ulong lid )
-{
-    int rc;
-    TRUSTREC dr, ur, rec;
-    ulong recno;
-
-    rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
-    if( rc ) {
-       log_error(_("lid %lu: read dir record failed: %s\n"),
-                                               lid, g10_errstr(rc));
-       return rc;
+    for( i = 0; i < pathlen; i++ )  {
+       if( highlight )
+           fputs(highlight == path[i].lid? "* ":"  ", fp );
+       rc = keyid_from_lid( path[i].lid, keyid );
+       if( rc )
+           fprintf(fp, "????????.%lu:", path[i].lid );
+       else
+           fprintf(fp,"%08lX.%lu:", (ulong)keyid[1], path[i].lid );
+       c = trust_letter(path[i].otrust);
+       if( c )
+           putc( c, fp );
+       else
+           fprintf( fp, "%02x", path[i].otrust );
+       putc('/', fp);
+       c = trust_letter(path[i].trust);
+       if( c )
+           putc( c, fp );
+       else
+           fprintf( fp, "%02x", path[i].trust );
+       putc(' ', fp);
+       p = get_user_id( keyid, &n );
+       putc(' ', fp);
+       putc('\"', fp);
+       print_string( fp, p, n > 40? 40:n, 0 );
+       putc('\"', fp);
+       m_free(p);
+       putc('\n', fp );
     }
-    tdbio_dump_record( &dr, stdout );
+}
+#endif
 
-    for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
-       rc = tdbio_read_record( recno, &rec, 0 );
-       if( rc ) {
-           log_error(_("lid %lu: read key record failed: %s\n"),
-                                               lid, g10_errstr(rc));
-           return rc;
-       }
-       tdbio_dump_record( &rec, stdout );
-    }
 
-    for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
-       rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
-       if( rc ) {
-           log_error(_("lid %lu: read uid record failed: %s\n"),
-                                               lid, g10_errstr(rc));
-           return rc;
-       }
-       tdbio_dump_record( &ur, stdout );
-       /* preference records */
-       for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
-           rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
-           if( rc ) {
-               log_error(_("lid %lu: read pref record failed: %s\n"),
-                                                   lid, g10_errstr(rc));
-               return rc;
-           }
-           tdbio_dump_record( &rec, stdout );
-       }
-       /* sig records */
-       for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
-           rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
-           if( rc ) {
-               log_error(_("lid %lu: read sig record failed: %s\n"),
-                                                   lid, g10_errstr(rc));
-               return rc;
-           }
-           tdbio_dump_record( &rec, stdout );
-       }
-    }
+static void
+print_default_uid( ulong lid )
+{
+    u32 keyid[2];
 
-    /* add cache record dump here */
+    if( !keyid_from_lid( lid, keyid ) )
+       print_user_id( "", keyid );
+}
 
 
+static void
+dump_tn_tree( int indent, TN tree )
+{
+    TN kr, ur;
 
-    return rc;
+    for( kr=tree; kr; kr = kr->next ) {
+       printf("%*s", indent*4, "" );
+       printf("K%lu(ot=%d,val=%d)  ", kr->lid,
+                                        kr->n.k.ownertrust,
+                                        kr->n.k.validity  );
+       print_default_uid( kr->lid );
+       for( ur=kr->list; ur; ur = ur->next ) {
+           printf("%*s  ", indent*4, "" );
+           printf("U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
+                                                ur->n.u.marginal_count,
+                                                ur->n.u.fully_count,
+                                                ur->n.u.validity
+                                           );
+           dump_tn_tree( indent+1, ur->list );
+       }
+    }
 }
 
 
+\f
+/***********************************************
+ ************* trustdb maintenance  ***********
+ ***********************************************/
 
-static TN
-new_tn(void)
+
+static void
+check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
+               TRUSTREC *sigrec, int sigidx, ulong hint_owner )
 {
-    TN t;
+    KBNODE node;
+    int rc, state;
+    byte uhash[20];
+    int is_selfsig;
+    PKT_signature *sigpkt = NULL;
+    TRUSTREC tmp;
+    u32 sigkid[2];
+    int revoked = 0;
 
-    if( used_tns ) {
-       t = used_tns;
-       used_tns = t->next;
-       memset( t, 0, sizeof *t );
+    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;
     }
-    else
-       t = m_alloc_clear( sizeof *t );
-    if( ++alloced_tns > max_alloced_tns )
-       max_alloced_tns = alloced_tns;
-    return t;
-}
+    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 );
 
 
-static void
-release_tn( TN t )
-{
-    if( t ) {
-       t->next = used_tns;
-       used_tns = t;
-       alloced_tns--;
+    /* 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 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
+                    || ( revoked = (sigpkt->sig_class == 0x30)) ) ) {
+               state = 2;
+               break; /* found */
+           }
+       }
+    }
+
+    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;
+    }
 
-static void
-release_tn_tree( TN kr )
-{
-    TN kr2;
+    /* FiXME: handling fo SIGF_REVOKED is not correct! */
 
-    for( ; kr; kr = kr2 ) {
-       release_tn_tree( kr->list );
-       kr2 = kr->next;
-       release_tn( kr );
+    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],
+                   revoked? _("Valid certificate revocation")
+                          : _("Good certificate") );
+       sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
+       if( revoked )
+           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;
 }
 
 
 /****************
- * Find all certification paths of a given LID.
- * Limit the search to MAX_DEPTH.  stack is a helper variable which
- * should have been allocated with size max_depth, stack[0] should
- * be setup to the key we are investigating, so the minimal depth
- * we should ever see in this function is 1.
- * Returns: a new tree
- * certchain_set must be a valid set or point to NULL; this function
- * may modifiy it.
+ * Process a hintlist.
+ * Fixme: this list is not anymore anchored to another
+ *       record, so it should be put elsewehere in case of an error
  */
-static TN
-build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
+static void
+process_hintlist( ulong hintlist, ulong hint_owner )
 {
-    TRUSTREC dirrec;
-    TRUSTREC uidrec;
-    ulong uidrno;
-    TN keynode;
+    ulong hlst_rn;
+    int rc;
 
-    if( depth >= max_depth )
-       return NULL;
+    for( hlst_rn = hintlist; hlst_rn; ) {
+       TRUSTREC hlstrec;
+       int hlst_idx;
 
-    keynode = new_tn();
-    if( !helproot )
-       helproot = keynode;
-    keynode->lid = lid;
-    if( !qry_lid_table_flag( ultikey_table, lid, NULL ) ) {
-       /* this is an ultimately trusted key;
-        * which means that we have found the end of the chain:
-        * We do this here prior to reading the dir record
-        * because we don't really need the info from that record */
-       keynode->n.k.ownertrust = TRUST_ULTIMATE;
-       keynode->n.k.buckstop   = 1;
-       return keynode;
-    }
-    read_record( lid, &dirrec, 0 );
-    if( dirrec.rectype != RECTYPE_DIR ) {
-       if( dirrec.rectype != RECTYPE_SDIR )
-           log_debug("lid %lu, has rectype %d"
-                     " - skipped\n", lid, dirrec.rectype );
-       m_free(keynode);
-       return NULL;
-    }
-    keynode->n.k.ownertrust = dirrec.r.dir.ownertrust;
+       read_record( hlst_rn, &hlstrec, RECTYPE_HLST );
 
-    /* loop over all user ids */
-    for( uidrno = dirrec.r.dir.uidlist; uidrno; uidrno = uidrec.r.uid.next ) {
-       TRUSTREC sigrec;
-       ulong sigrno;
-       TN uidnode = NULL;
-
-       read_record( uidrno, &uidrec, RECTYPE_UID );
-
-       if( !(uidrec.r.uid.uidflags & UIDF_CHECKED) )
-           continue; /* user id has not been checked */
-       if( !(uidrec.r.uid.uidflags & UIDF_VALID) )
-           continue; /* user id is not valid */
-       if( (uidrec.r.uid.uidflags & UIDF_REVOKED) )
-           continue; /* user id has been revoked */
+       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;
 
-       /* loop over all signature records */
-       for(sigrno=uidrec.r.uid.siglist; sigrno; sigrno = sigrec.r.sig.next ) {
-           int i;
-           TN tn;
+           lid = hlstrec.r.hlst.rnum[hlst_idx];
+           if( !lid )
+               continue;
 
-           read_record( sigrno, &sigrec, RECTYPE_SIG );
+           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;
+           }
 
-           for(i=0; i < SIGS_PER_RECORD; i++ ) {
-               if( !sigrec.r.sig.sig[i].lid )
-                   continue; /* skip deleted sigs */
-               if( !(sigrec.r.sig.sig[i].flag & SIGF_CHECKED) )
-                   continue; /* skip unchecked signatures */
-               if( !(sigrec.r.sig.sig[i].flag & SIGF_VALID) )
-                   continue; /* skip invalid signatures */
-               if( (sigrec.r.sig.sig[i].flag & SIGF_EXPIRED) )
-                   continue; /* skip expired signatures */
-               if( (sigrec.r.sig.sig[i].flag & SIGF_REVOKED) )
-                   continue; /* skip revoked signatures */
-               /* check for cycles */
-               for( tn=keynode; tn && tn->lid != sigrec.r.sig.sig[i].lid;
-                                                         tn = tn->back )
-                   ;
-               if( tn )
-                   continue; /* cycle found */
+           /* 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 );
 
-               tn = build_cert_tree( sigrec.r.sig.sig[i].lid,
-                                     depth+1, max_depth, helproot );
-               if( !tn )
-                   continue; /* cert chain too deep or error */
+           /* 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;
 
-               if( !uidnode ) {
-                   uidnode = new_tn();
-                   uidnode->back = keynode;
-                   uidnode->lid = uidrno;
-                   uidnode->is_uid = 1;
-                   uidnode->next = keynode->list;
-                   keynode->list = uidnode;
-               }
+               read_record( r1, &uidrec, RECTYPE_UID );
+               for( r2 = uidrec.r.uid.siglist; r2; r2 = sigrec.r.sig.next ) {
+                   int i;
 
-               tn->back = uidnode;
-               tn->next = uidnode->list;
-               uidnode->list = tn;
-             #if 0 /* optimazation - fixme: reenable this later */
-               if( tn->n.k.buckstop ) {
-                   /* ultimately trusted key found:
-                    * no need to check more signatures of this uid */
-                   sigrec.r.sig.next = 0;
-                   break;
+                   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 );
                }
-             #endif
            }
-       } /* end loop over sig recs */
-    } /* end loop over user ids */
-
-    if( !keynode->list ) {
-       release_tn_tree( keynode );
-       keynode = NULL;
-    }
+           release_kbnode( keyblock );
+       } /* loop over hlst entries */
 
-    return keynode;
+       /* delete this hlst record */
+       hlst_rn = hlstrec.r.hlst.next;
+       delete_record( hlstrec.recnum );
+    } /* loop over hintlist */
 }
 
 
-
-
 /****************
- * 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.
+ * Create or update shadow dir record and return the LID of the record
  */
-static int
-verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
+static ulong
+create_shadow_dir( PKT_signature *sig, ulong lid  )
 {
-    TN tree;
-    int trust;
-
-    tree = build_cert_tree( drec->r.dir.lid, 0, opt.max_cert_depth, NULL );
-    if( !tree )
-       return TRUST_UNDEFINED;
-    trust = propagate_validity( tree );
-    if( namehash ) {
-       /* find the matching user id.
-        * FIXME: the way we handle this is too inefficient */
-       TN ur;
-       TRUSTREC rec;
+    TRUSTREC sdir, hlst, tmphlst;
+    ulong recno, newlid;
+    int tmpidx=0; /* avoids gcc warnign - this is controlled by tmphlst */
+    int rc;
 
-       trust = 0;
-       for( ur=tree->list; ur; ur = ur->next ) {
-           read_record( ur->lid, &rec, RECTYPE_UID );
-           if( !memcmp( namehash, rec.r.uid.namehash, 20 ) ) {
-               trust = ur->n.u.validity;
-               break;
+    /* 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));
+       tdbio_invalid();
+    }
+    if( rc == -1 ) { /* not found: create */
+       memset( &sdir, 0, sizeof sdir );
+       sdir.recnum = tdbio_new_recnum();
+       sdir.rectype= RECTYPE_SDIR;
+       sdir.r.sdir.lid = sdir.recnum;
+       sdir.r.sdir.keyid[0] = sig->keyid[0];
+       sdir.r.sdir.keyid[1] = sig->keyid[1];
+       sdir.r.sdir.pubkey_algo = sig->pubkey_algo;
+       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 */
        }
     }
+    /* 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 );
+    }
 
-    release_tn_tree( tree );
-    return trust;
+    return newlid;
 }
 
 
-
-
 /****************
- * we have the pubkey record and all needed informations are in the trustdb
- * but nothing more is known.
+ * 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 int
-do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
+static void
+upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
+               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
 {
-    if( !dr->r.dir.keylist ) {
-       log_error(_("Ooops, no keys\n"));
-       return G10ERR_TRUSTDB;
-    }
-    if( !dr->r.dir.uidlist ) {
-       log_error(_("Ooops, no user ids\n"));
-       return G10ERR_TRUSTDB;
-    }
+    TRUSTREC 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( namehash ) {
-       /* Fixme: use the cache */
-       *validity = verify_key( opt.max_cert_depth, dr, namehash );
+    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;
     }
-    else 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, NULL );
-       if( (*validity & TRUST_MASK) >= TRUST_UNDEFINED
-           && tdbio_db_matches_options() ) {
-           /* update the cached validity value */
-           /* FIXME: Move this to another place so that we can
-            * update the validity of the uids too */
-           dr->r.dir.validity = (*validity & TRUST_MASK);
-           dr->r.dir.dirflags |= DIRF_VALVALID;
-           write_record( dr );
+    if( recno ) { /* yes */
+       ins_recno_list( recno_list, recno, RECTYPE_KEY );
+    }
+    else { /* no: insert this new key */
+       recheck = 1; /* same as recheck */
+       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;
        }
     }
 
-    if( dr->r.dir.dirflags & DIRF_REVOKED )
-       *validity |= TRUST_FLAG_REVOKED;
-
-    return 0;
-}
+    if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) )
+       return;
 
-\f
-/****************
- * Perform some checks over the trustdb
- *  level 0: only open the db
- *       1: used for initial program startup
- */
-int
-init_trustdb( int level, const char *dbname )
-{
-    /* just store the args */
-    if( trustdb_args.init )
-       return 0;
-    trustdb_args.level = level;
-    trustdb_args.dbname = dbname? m_strdup(dbname): NULL;
-    return 0;
-}
+    /* 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;
+    }
 
-static void
-do_init_trustdb()
-{
-    int rc=0;
-    int level = trustdb_args.level;
-    const char* dbname = trustdb_args.dbname;
+    for( node=keynode->next; node; node = node->next ) {
+       PKT_signature *sig;
 
-    trustdb_args.init = 1;
+       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+           break; /* ready (we check only one key at a time) */
+       else if( node->pkt->pkttype != PKT_SIGNATURE )
+           continue;
 
-    if( !ultikey_table )
-       ultikey_table = new_lid_table();
+       sig = node->pkt->pkt.signature;
 
-    if( !level || level==1 ) {
-       rc = tdbio_set_dbname( dbname, !!level );
-       if( !rc ) {
-           if( !level )
-               return;
+       if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
+           continue; /* here we only care about a self-signatures */
 
-           /* verify that our own keys are in the trustDB
-            * or move them to the trustdb. */
-           rc = verify_own_keys();
+       if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
+           if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
+               continue; /* oops, ignore subkey binding on main key */
 
-           /* should we check whether there is no other ultimately trusted
-            * key in the database? */
+           /* 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
-       BUG();
-    if( rc )
-       log_fatal("can't init trustdb: %s\n", g10_errstr(rc) );
-}
-
-
-void
-list_trustdb( const char *username )
-{
-    TRUSTREC rec;
-
-    INIT_TRUSTDB();
-
-    if( username && *username == '#' ) {
-       int rc;
-       ulong lid = atoi(username+1);
+       else if( sig->sig_class == 0x20 && !revoke_seen ) {
+           if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+               continue; /* a subkey is not expected here */
 
-       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( 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_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 );
+           /* 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;
+       }
     }
-    else {
-       ulong recnum;
-       int i;
 
-       printf("TrustDB: %s\n", tdbio_get_dbname() );
-       for(i=9+strlen(tdbio_get_dbname()); i > 0; i-- )
-           putchar('-');
-       putchar('\n');
-       for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ )
-           tdbio_dump_record( &rec, stdout );
-    }
+    write_record( &krec );
 }
 
+
 /****************
- * Print a list of all defined owner trust value.
+ * 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.
  */
-void
-export_ownertrust()
+static void
+upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
+               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
 {
-    TRUSTREC rec;
-    TRUSTREC rec2;
-    ulong recnum;
-    int i;
-    byte *p;
+    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;
 
-    INIT_TRUSTDB();
-    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( DBG_TRUST )
+       log_debug("upd_uid_record for %08lX/%02X%02X\n",
+                              (ulong)keyid[1], uidhash[18], uidhash[19]);
+
+    /* 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; /* insert is the same as a recheck */
+       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) ) {
+       unsigned orig_uidflags = urec.r.uid.uidflags;
 
-void
-import_ownertrust( const char *fname )
-{
-    FILE *fp;
-    int is_stdin=0;
-    char line[256];
-    char *p;
-    size_t n, fprlen;
-    unsigned otrust;
+       urec.r.uid.uidflags = 0;
+       /* first check regular self signatures */
+       for( node=uidnode->next; node; node = node->next ) {
+           PKT_signature *sig;
 
-    INIT_TRUSTDB();
-    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( node->pkt->pkttype == PKT_USER_ID )
+               break; /* ready */
+           if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+               break; /* ready */
+           if( node->pkt->pkttype != PKT_SIGNATURE )
+               continue;
 
-    while( fgets( line, DIM(line)-1, fp ) ) {
-       TRUSTREC rec;
-       int rc;
+           sig = node->pkt->pkt.signature;
 
-       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 */
-       }
-       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 );
+           if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
+               continue; /* not a self signature */
 
-           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"));
+           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 {
-                   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) );
+                   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 /* 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();
-}
 
+       /* and now check for revocations- we must do this after the
+        * self signature check because a selfsignature which is newer
+        * than a revocation makes the revocation invalid.
+        * Fixme: Is this correct - check with rfc2440
+        */
+       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;
 
-#if 0
-static void
-print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
-{
-    int rc, c, i;
-    u32 keyid[2];
-    char *p;
-    size_t n;
-
-    for( i = 0; i < pathlen; i++ )  {
-       if( highlight )
-           fputs(highlight == path[i].lid? "* ":"  ", fp );
-       rc = keyid_from_lid( path[i].lid, keyid );
-       if( rc )
-           fprintf(fp, "????????.%lu:", path[i].lid );
-       else
-           fprintf(fp,"%08lX.%lu:", (ulong)keyid[1], path[i].lid );
-       c = trust_letter(path[i].otrust);
-       if( c )
-           putc( c, fp );
-       else
-           fprintf( fp, "%02x", path[i].otrust );
-       putc('/', fp);
-       c = trust_letter(path[i].trust);
-       if( c )
-           putc( c, fp );
-       else
-           fprintf( fp, "%02x", path[i].trust );
-       putc(' ', fp);
-       p = get_user_id( keyid, &n );
-       putc(' ', fp);
-       putc('\"', fp);
-       print_string( fp, p, n > 40? 40:n, 0 );
-       putc('\"', fp);
-       m_free(p);
-       putc('\n', fp );
-    }
-}
-#endif
-
+           sig = node->pkt->pkt.signature;
 
+           if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
+               continue; /* not a self signature */
 
-static int
-propagate_validity( TN node )
-{
-    TN kr, ur;
-    int max_validity = 0;
+           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) );
+               }
+           }
 
-    assert( !node->is_uid );
-    if( node->n.k.ownertrust == TRUST_ULTIMATE ) {
-       /* this is one of our keys */
-       assert( !node->list ); /* This should be a leaf */
-       return TRUST_ULTIMATE;
-    }
+       }
 
-    /* loop over all user ids */
-    for( ur=node->list; ur; ur = ur->next ) {
-       assert( ur->is_uid );
-       /* loop over all signators */
-       for(kr=ur->list; kr; kr = kr->next ) {
-           int val = propagate_validity( kr );
+       if( orig_uidflags != urec.r.uid.uidflags ) {
+           write_record( &urec );
+           if(   !( urec.r.uid.uidflags & UIDF_VALID )
+               || ( urec.r.uid.uidflags & UIDF_REVOKED ) )
+               ; /*FIXME: mark as modified down */
+           else
+               ; /*FIXME: mark as modified up (maybe a new uuser id)*/
 
-           if( val == TRUST_ULTIMATE ) {
-               ur->n.u.fully_count = opt.completes_needed;
-           }
-           else if( val == TRUST_FULLY ) {
-               if( kr->n.k.ownertrust == TRUST_FULLY )
-                   ur->n.u.fully_count++;
-               else if( kr->n.k.ownertrust == TRUST_MARGINAL )
-                   ur->n.u.marginal_count++;
-           }
        }
-       /* fixme: We can move this test into the loop to stop as soon as
-        * we have a level of FULLY and return from this function
-        * We dont do this now to get better debug output */
-       if( ur->n.u.fully_count >= opt.completes_needed
-           || ur->n.u.marginal_count >= opt.marginals_needed )
-           ur->n.u.validity = TRUST_FULLY;
-       else if( ur->n.u.fully_count || ur->n.u.marginal_count )
-           ur->n.u.validity = TRUST_MARGINAL;
 
-       if( ur->n.u.validity >= max_validity )
-           max_validity = ur->n.u.validity;
-    }
+    } /* end check self-signatures */
 
-    node->n.k.validity = max_validity;
-    return max_validity;
-}
 
+    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 );
 
-static void
-print_default_uid( ulong lid )
-{
-    u32 keyid[2];
+    /* Now we va check the certication signatures */
+    for( node=uidnode->next; node; node = node->next ) {
+       PKT_signature *sig;
 
-    if( !keyid_from_lid( lid, keyid ) )
-       print_user_id( "", keyid );
-}
+       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;
 
-static void
-dump_tn_tree( int indent, TN tree )
-{
-    TN kr, ur;
+       if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] )
+           continue; /* here we skip the self-signatures */
 
-    for( kr=tree; kr; kr = kr->next ) {
-       printf("%*s", indent*4, "" );
-       printf("K%lu(ot=%d,val=%d)  ", kr->lid,
-                                        kr->n.k.ownertrust,
-                                        kr->n.k.validity  );
-       print_default_uid( kr->lid );
-       for( ur=kr->list; ur; ur = ur->next ) {
-           printf("%*s  ", indent*4, "" );
-           printf("U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
-                                                ur->n.u.marginal_count,
-                                                ur->n.u.fully_count,
-                                                ur->n.u.validity
-                                           );
-           dump_tn_tree( indent+1, ur->list );
+       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 );
 }
 
 
-void
-list_trust_path( const char *username )
+static void
+upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
 {
-    int rc;
-    ulong lid;
-    TRUSTREC rec;
-    TN tree;
-    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-
-    INIT_TRUSTDB();
-    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 );
-       }
-    }
-    lid = pk->local_id;
-    free_public_key( pk );
+    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;
 
-    tree = build_cert_tree( lid, 0, opt.max_cert_depth, NULL );
-    if( tree )
-       propagate_validity( tree );
-    dump_tn_tree( 0, tree );
-    printf("(alloced tns=%d  max=%d)\n", alloced_tns, max_alloced_tns );
-    release_tn_tree( tree );
-}
+    if( DBG_TRUST )
+       log_debug("upd_pref_record for %08lX.%lu/%02X%02X\n",
+                         (ulong)keyid[1], lid, uidhash[18], uidhash[19] );
 
 
-/****************
- * 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];
-
-    INIT_TRUSTDB();
-    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));
+    /* 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;
+           }
        }
-       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 );
-
+    }
+    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( 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;
-               }
+    if( n_prefs_sig == n_prefs_rec
+       && !memcmp( prefs_sig, prefs_rec, n_prefs_sig ) )
+       return;  /* not changed */
 
-               read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY );
+    /* 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 );
+    }
 
-               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;
-               }
+    if( n_prefs_sig > ITEMS_PER_PREF_RECORD )
+        log_info(_("WARNING: can't yet handle long pref records\n"));
 
-               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 );
+    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;
+       byte *pp = prefs_sig;
 
-               release_kbnode( keyblock ); keyblock = NULL;
-               if( !(++count % 100) )
-                   log_info(_("%lu keys so far processed\n"), count);
+       n = n_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;
            }
-       }
-       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);
+           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;
 }
 
 
-/****************
- * Put new entries  from the pubrings into the trustdb.
- * This function honors the sig flags to speed up the check.
- */
-void
-update_trustdb( )
+/* FIXME: add logic to set the modify_{down,up} */
+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 revoked )
 {
-    KBNODE keyblock = NULL;
-    KBPOS kbpos;
+    /* 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 when the missing public key
+     * gets 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;
+    ulong pk_lid = 0;
+    int found_sig = 0;
+    int found_delrec = 0;
     int rc;
 
-    if( opt.dry_run )
-       return;
 
-    INIT_TRUSTDB();
-    rc = enum_keyblocks( 0, &kbpos, &keyblock );
-    if( !rc ) {
-       ulong count=0, upd_count=0, err_count=0, new_count=0;
+    if( DBG_TRUST )
+       log_debug("upd_cert_record for %08lX.?/%02X%02X/%08lX\n",
+                             (ulong)keyid[1], uidhash[18],
+                              uidhash[19], (ulong)sig->keyid[1] );
 
-       while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
-           int modified;
+    delrec.recnum = 0;
 
-           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++;
+    /* get the LID of the pubkey of the signature under verification */
+    pk_lid = lid_from_keyid( sig->keyid );
+
+    /* 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 ) {
+               /* (remember this unused slot) */
+               if( !found_delrec && !delrec.recnum ) {
+                   delrec = rec;
+                   delrecidx = i;
+                   found_delrec=1;
                }
+               continue; /* skip unused slots */
            }
-           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) );
 
-           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 PK.
- * Note: This does not ask any questions
- * Returns: 0 okay of an errorcode
- *
- * It operates this way:
- *  locate the pk in the trustdb
- *     found:
- *         Do we have a valid cache record for it?
- *             yes: return trustlevel from cache
- *             no:  make a cache record and all the other stuff
- *     not found:
- *         try to insert the pubkey into the trustdb and check again
- *
- * Problems: How do we get the complete keyblock to check that the
- *          cache record is actually valid?  Think we need a clever
- *          cache in getkey.c  to keep track of this stuff. Maybe it
- *          is not necessary to check this if we use a local pubring. Hmmmm.
- */
-int
-check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte *namehash )
-{
-    TRUSTREC rec;
-    unsigned trustlevel = TRUST_UNKNOWN;
-    int rc=0;
-    u32 cur_time;
-    u32 keyid[2];
-
-
-    INIT_TRUSTDB();
-    keyid_from_pk( pk, keyid );
+           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 && !revoked && (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 */
 
-    /* get the pubkey record */
-    if( pk->local_id ) {
-       read_record( pk->local_id, &rec, RECTYPE_DIR );
-    }
-    else { /* no local_id: scan the trustdb */
-       if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 ) {
-           log_error(_("check_trust: search dir record failed: %s\n"),
-                                                           g10_errstr(rc));
-           return rc;
-       }
-       else if( rc == -1 ) { /* not found - insert */
-           rc = insert_trust_record( pk );
-           if( rc ) {
-               log_error(_("key %08lX: insert trust record failed: %s\n"),
-                                         (ulong)keyid[1], g10_errstr(rc));
-               goto leave;
+           read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
+           if( tmp.rectype == RECTYPE_DIR ) {
+               /* the public key is in the trustdb: check sig */
+               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],
+                               revoked? _("Valid certificate revocation")
+                                      : _("Good certificate") );
+                   rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
+                   if( revoked ) /* we are investigating revocations */
+                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
+               }
+               else if( rc == G10ERR_NO_PUBKEY ) {
+                   /* This may happen if the key is still in the trustdb
+                    * but not available in the keystorage */
+                   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],
+                                _("public key not anymore available") );
+                   rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
+                   if( revoked )
+                       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],
+                               revoked? _("Invalid certificate revocation")
+                                      : _("Invalid certificate"),
+                                                   g10_errstr(rc));
+                   rec.r.sig.sig[i].flag = SIGF_CHECKED;
+                   if( revoked )
+                       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( revoked )
+                       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 );
+               tdbio_invalid();
            }
-           log_info(_("key %08lX.%lu: inserted into trustdb\n"),
-                                         (ulong)keyid[1], pk->local_id );
-           /* and re-read the dir record */
-           read_record( pk->local_id, &rec, RECTYPE_DIR );
        }
-    }
-    cur_time = make_timestamp();
-    if( pk->timestamp > cur_time ) {
-       log_info(_("key %08lX.%lu: created in future "
-                  "(time warp or clock problem)\n"),
-                                         (ulong)keyid[1], pk->local_id );
-       return G10ERR_TIME_CONFLICT;
-    }
-
-    if( pk->expiredate && pk->expiredate <= cur_time ) {
-       log_info(_("key %08lX.%lu: expired at %s\n"),
-                       (ulong)keyid[1], pk->local_id,
-                            asctimestamp( pk->expiredate) );
-        trustlevel = TRUST_EXPIRED;
-    }
-    else {
-       rc = do_check( &rec, &trustlevel, namehash );
-       if( rc ) {
-           log_error(_("key %08lX.%lu: trust check failed: %s\n"),
-                           (ulong)keyid[1], pk->local_id, g10_errstr(rc));
-           return rc;
+       if( found_delrec && delrec.recnum ) {
+           delrec = rec;
+           found_delrec = 0; /* we only want the first one */
        }
-    }
-
-
-  leave:
-    if( DBG_TRUST )
-       log_debug("check_trust() returns trustlevel %04x.\n", trustlevel);
-    *r_trustlevel = trustlevel;
-    return 0;
-}
-
-
-
-
-int
-query_trust_info( PKT_public_key *pk, const byte *namehash )
-{
-    unsigned trustlevel;
-    int c;
-
-    INIT_TRUSTDB();
-    if( check_trust( pk, &trustlevel, namehash ) )
-       return '?';
-    if( trustlevel & TRUST_FLAG_REVOKED )
-       return 'r';
-    c = trust_letter( (trustlevel & TRUST_MASK) );
-    if( !c )
-       c = '?';
-    return c;
-}
-
-
-
-/****************
- * Enumerate all keys, which are needed to build all trust paths for
- * the given key.  This function does not return the key itself or
- * the ultimate key (the last point in cerificate chain).  Only
- * certificate chains which ends up at an ultimately trusted key
- * are listed. If ownertrust or validity is not NULL, the corresponding
- * value for the returned LID is also returned in these variable(s).
- *
- *  1) create a void pointer and initialize it to NULL
- *  2) pass this void pointer by reference to this function.
- *     Set lid to the key you want to enumerate and pass it by reference.
- *  3) call this function as long as it does not return -1
- *     to indicate EOF. LID does contain the next key used to build the web
- *  4) Always call this function a last time with LID set to NULL,
- *     so that it can free its context.
- *
- * Returns: -1 on EOF or the level of the returned LID
- */
-int
-enum_cert_paths( void **context, ulong *lid,
-                unsigned *ownertrust, unsigned *validity )
-{
-    return -1;
-  #if 0
-    struct enum_cert_paths_ctx *ctx;
-    fixme: .....   tsl;
-
-    INIT_TRUSTDB();
-    if( !lid ) {  /* release the context */
-       if( *context ) {
-           FIXME: ........tsl2;
-
-           ctx = *context;
-           for(tsl = ctx->tsl_head; tsl; tsl = tsl2 ) {
-               tsl2 = tsl->next;
-               m_free( tsl );
-           }
-           *context = NULL;
+       if( rec.dirty ) {
+           write_record( &rec );
+           rec.dirty = 0;
        }
-       return -1;
     }
 
-    if( !*context ) {
-       FIXME .... *tmppath;
-       TRUSTREC rec;
+    if( found_sig )
+       return;
 
-       if( !*lid )
-           return -1;
+    /* 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. */
 
-       ctx = m_alloc_clear( sizeof *ctx );
-       *context = ctx;
-       /* collect the paths */
-      #if 0
-       read_record( *lid, &rec, RECTYPE_DIR );
-       tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
-       tsl = NULL;
-       collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &tsl );
-       m_free( tmppath );
-       sort_tsl_list( &tsl );
-      #endif
-       /* setup the context */
-       ctx->tsl_head = tsl;
-       ctx->tsl = ctx->tsl_head;
-       ctx->idx = 0;
-    }
+    if( !pk_lid ) /* we have already seen that there is no pubkey */
+       rc = G10ERR_NO_PUBKEY;
     else
-       ctx = *context;
+       rc = check_key_signature( keyblock, signode, NULL );
 
-    while( ctx->tsl && ctx->idx >= ctx->tsl->pathlen ) {
-       ctx->tsl = ctx->tsl->next;
-       ctx->idx = 0;
+    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],
+                               revoked? _("Valid certificate revocation")
+                                      : _("Good certificate") );
+       newlid = pk_lid;  /* this is the pk of the signature */
+       newflag = SIGF_CHECKED | SIGF_VALID;
+       if( revoked )
+           newflag |= SIGF_REVOKED;
+    }
+    else if( rc == G10ERR_NO_PUBKEY ) {
+       if( opt.verbose > 1 || DBG_TRUST )
+           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( revoked )
+           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],
+               revoked? _("Invalid certificate revocation")
+                      : _("Invalid certificate"),
+                                           g10_errstr(rc));
+       newlid = create_shadow_dir( sig, lid );
+       newflag = SIGF_CHECKED;
+       if( revoked )
+           newflag |= SIGF_REVOKED;
     }
-    tsl = ctx->tsl;
-    if( !tsl )
-       return -1; /* eof */
-
-    if( ownertrust )
-       *ownertrust = tsl->path[ctx->idx].otrust;
-    if( validity )
-       *validity = tsl->path[ctx->idx].trust;
-    *lid = tsl->path[ctx->idx].lid;
-    ctx->idx++;
-    return ctx->idx-1;
-  #endif
-}
-
-
-/****************
- * Print the current path
- */
-void
-enum_cert_paths_print( void **context, FILE *fp,
-                                      int refresh, ulong selected_lid )
-{
-    return;
-  #if 0
-    struct enum_cert_paths_ctx *ctx;
-    FIXME......... tsl;
-
-    if( !*context )
-       return;
-    INIT_TRUSTDB();
-    ctx = *context;
-    if( !ctx->tsl )
-       return;
-    tsl = ctx->tsl;
-
-    if( !fp )
-       fp = stderr;
-
-    if( refresh ) { /* update the ownertrust and if possible the validity */
-       int i;
-       int match = tdbio_db_matches_options();
-
-       for( i = 0; i < tsl->pathlen; i++ )  {
-           TRUSTREC rec;
 
-           read_record( tsl->path[i].lid, &rec, RECTYPE_DIR );
-           tsl->path[i].otrust = rec.r.dir.ownertrust;
-           /* update validity only if we have it in the cache
-            * calculation is too time consuming */
-           if( match && (rec.r.dir.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;
-           }
-       }
+    if( delrec.recnum ) { /* we can reuse an unused slot */
+       delrec.r.sig.sig[delrecidx].lid = newlid;
+       delrec.r.sig.sig[delrecidx].flag= newflag;
+       write_record( &delrec );
     }
+    else { /* we must insert a new sig record */
+       TRUSTREC tmp;
 
-    print_path( tsl->pathlen, tsl->path, fp, selected_lid );
-  #endif
+       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;
+    }
 }
 
 
 /****************
- * Return the assigned ownertrust value for the given LID
+ * 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().
  */
-unsigned
-get_ownertrust( ulong lid )
+int
+update_trust_record( KBNODE keyblock, int recheck, int *modified )
 {
-    TRUSTREC rec;
+    PKT_public_key *primary_pk;
+    KBNODE node;
+    TRUSTREC drec;
+    TRUSTREC krec;
+    TRUSTREC urec;
+    TRUSTREC prec;
+    TRUSTREC helprec;
+    int rc = 0;
+    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 */
 
-    INIT_TRUSTDB();
-    read_record( lid, &rec, RECTYPE_DIR );
-    return rec.r.dir.ownertrust;
-}
+    if( opt.dry_run )
+       return 0;
 
-int
-get_ownertrust_info( ulong lid )
-{
-    unsigned otrust;
-    int c;
+    init_trustdb();
+    if( modified )
+       *modified = 0;
 
-    INIT_TRUSTDB();
-    otrust = get_ownertrust( lid );
-    c = trust_letter( (otrust & TRUST_MASK) );
-    if( !c )
-       c = '?';
-    return c;
-}
+    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;
 
-/*
- * 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 allocated 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;
+    keyid_from_pk( primary_pk, keyid );
 
-    INIT_TRUSTDB();
-    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;
-       }
-    }
-    return NULL;
-}
+    /* 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 );
+    }
 
-/****************
- * Check whether the algorithm is in one of the pref records
- */
-int
-is_algo_in_prefs( ulong lid, int preftype, int algo )
-{
-    TRUSTREC rec;
-    ulong recno;
-    int i;
-    byte *pref;
+    /* 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;
+           }
+       }
 
-    INIT_TRUSTDB();
-    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;
+       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;
     }
-    return 0;
-}
 
 
-static int
-get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
-{
-    int rc=0;
 
-    if( pk->local_id ) {
-       read_record( pk->local_id, rec, RECTYPE_DIR );
-    }
-    else { /* no local_id: scan the trustdb */
-       if( (rc=tdbio_search_dir_bypk( pk, rec )) && rc != -1 )
-           log_error(_("get_dir_record: search_record failed: %s\n"),
-                                                           g10_errstr(rc));
+    if( rc )
+       rc = tdbio_cancel_transaction();
+    else {
+       if( modified && tdbio_is_dirty() )
+           *modified = 1;
+       drec.r.dir.dirflags |= DIRF_CHECKED;
+       drec.r.dir.valcheck = 0;
+       write_record( &drec );
+       rc = tdbio_end_transaction();
     }
+    rel_recno_list( &recno_list );
     return rc;
 }
 
 
-
 /****************
- * This function simply looks for the key in the trustdb
- * and makes sure that pk->local_id is set to the correct value.
- * Return: 0 = found
- *        -1 = not found
- *       other = error
+ * Insert a trust record into the TrustDB
+ * This function assumes that the record does not yet exist.
  */
 int
-query_trust_record( PKT_public_key *pk )
-{
-    TRUSTREC rec;
-    INIT_TRUSTDB();
-    return get_dir_record( pk, &rec );
-}
-
-
-int
-clear_trust_checked_flag( PKT_public_key *pk )
-{
-    TRUSTREC rec;
-    int rc;
-
-    if( opt.dry_run )
-       return 0;
-
-    INIT_TRUSTDB();
-    rc = get_dir_record( pk, &rec );
-    if( rc )
-       return rc;
-
-    /* check whether they are already reset */
-    if(   !(rec.r.dir.dirflags & DIRF_CHECKED)
-       && !(rec.r.dir.dirflags & DIRF_VALVALID) )
-       return 0;
-
-    /* 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 )
+insert_trust_record( PKT_public_key *pk )
 {
+    TRUSTREC dirrec;
+    TRUSTREC shadow;
+    KBNODE keyblock = NULL;
     KBNODE node;
-    int rc, state;
-    byte uhash[20];
-    int is_selfsig;
-    PKT_signature *sigpkt = NULL;
-    TRUSTREC tmp;
-    u32 sigkid[2];
-    int revoked = 0;
+    byte fingerprint[MAX_FINGERPRINT_LEN];
+    size_t fingerlen;
+    int rc = 0;
+    ulong hintlist = 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( opt.dry_run )
+       return 0;
+
+    init_trustdb();
+
+    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 - this is 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;
     }
-    if( !tmp.r.dir.keylist ) {
-       log_error(_("lid %lu: no primary key\n"), tmp.r.dir.lid );
-       return;
+
+    if( pk->local_id ) {
+       log_debug("insert_trust_reord with pk->local_id=%lu\n", pk->local_id );
+       rc = update_trust_record( keyblock, 1, NULL );
+       release_kbnode( keyblock );
+       return rc;
     }
-    read_record(tmp.r.dir.keylist, &tmp, RECTYPE_KEY );
-    keyid_from_fingerprint( tmp.r.key.fingerprint,
-                           tmp.r.key.fingerprint_len, sigkid );
 
+    /* check that we used the primary key (we are little bit paranoid) */
+    {  PKT_public_key *a_pk;
+       u32 akid[2], bkid[2];
 
-    /* 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;
+       node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+       a_pk = node->pkt->pkt.public_key;
 
-           if( state )
-               break;
-           rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
-           if( !memcmp( uhash, uidrec_hash, 20 ) )
-               state = 1;
-       }
-       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
-                    || ( revoked = (sigpkt->sig_class == 0x30)) ) ) {
-               state = 2;
-               break; /* found */
-           }
+       /* 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 );
+
+       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;
        }
     }
 
-    if( !node ) {
-       log_info(_("lid %lu: user id not found in keyblock\n"), lid );
-       return ;
+    /* 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));
+       tdbio_invalid();
     }
-    if( state != 2 ) {
-       log_info(_("lid %lu: user id without signature\n"), lid );
-       return ;
+    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 );
 
-    /* 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;
+    /* out the LID into the keyblock */
+    pk->local_id = dirrec.r.dir.lid;
+    for( node=keyblock; node; node = node->next ) {
+       if( node->pkt->pkttype == PKT_PUBLIC_KEY
+           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+           PKT_public_key *a_pk = node->pkt->pkt.public_key;
+           a_pk->local_id = dirrec.r.dir.lid;
+       }
+       else if( node->pkt->pkttype == PKT_SIGNATURE ) {
+           PKT_signature *a_sig = node->pkt->pkt.signature;
+           a_sig->local_id = dirrec.r.dir.lid;
+       }
     }
 
-    /* FiXME: handling fo SIGF_REVOKED is not correct! */
+    /* FIXME: mark tdb as modified upwards */
 
-    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],
-                   revoked? _("Valid certificate revocation")
-                          : _("Good certificate") );
-       sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
-       if( revoked )
-           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;
+    /* 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;
 }
 
 
+
+\f
+/***********************************************
+ *********  Trust calculation  *****************
+ ***********************************************/
+
 /****************
- * Process a hintlist.
- * Fixme: this list is not anymore anchored to another
- *       record, so it should be put elsewehere in case of an error
+ * Find all certification paths of a given LID.
+ * Limit the search to MAX_DEPTH.  stack is a helper variable which
+ * should have been allocated with size max_depth, stack[0] should
+ * be setup to the key we are investigating, so the minimal depth
+ * we should ever see in this function is 1.
+ * Returns: a new tree
+ * certchain_set must be a valid set or point to NULL; this function
+ * may modifiy it.
+ *
+ * Fixme: add a fastscan mode which stops ad valid validity nodes.
  */
-static void
-process_hintlist( ulong hintlist, ulong hint_owner )
+static TN
+build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
 {
-    ulong hlst_rn;
-    int rc;
-
-    for( hlst_rn = hintlist; hlst_rn; ) {
-       TRUSTREC hlstrec;
-       int hlst_idx;
-
-       read_record( hlst_rn, &hlstrec, RECTYPE_HLST );
-
-       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;
-
-           lid = hlstrec.r.hlst.rnum[hlst_idx];
-           if( !lid )
-               continue;
+    TRUSTREC dirrec;
+    TRUSTREC uidrec;
+    ulong uidrno;
+    TN keynode;
 
-           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;
-           }
+    if( depth >= max_depth )
+       return NULL;
 
-           /* 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 );
+    keynode = new_tn();
+    if( !helproot )
+       helproot = keynode;
+    keynode->lid = lid;
+    if( !qry_lid_table_flag( ultikey_table, lid, NULL ) ) {
+       /* this is an ultimately trusted key;
+        * which means that we have found the end of the chain:
+        * We do this here prior to reading the dir record
+        * because we don't really need the info from that record */
+       keynode->n.k.ownertrust = TRUST_ULTIMATE;
+       keynode->n.k.buckstop   = 1;
+       return keynode;
+    }
+    read_record( lid, &dirrec, 0 );
+    if( dirrec.rectype != RECTYPE_DIR ) {
+       if( dirrec.rectype != RECTYPE_SDIR )
+           log_debug("lid %lu, has rectype %d"
+                     " - skipped\n", lid, dirrec.rectype );
+       m_free(keynode);
+       return NULL;
+    }
+    keynode->n.k.ownertrust = dirrec.r.dir.ownertrust;
 
-           /* 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;
+    /* loop over all user ids */
+    for( uidrno = dirrec.r.dir.uidlist; uidrno; uidrno = uidrec.r.uid.next ) {
+       TRUSTREC sigrec;
+       ulong sigrno;
+       TN uidnode = NULL;
 
-               read_record( r1, &uidrec, RECTYPE_UID );
-               for( r2 = uidrec.r.uid.siglist; r2; r2 = sigrec.r.sig.next ) {
-                   int i;
+       read_record( uidrno, &uidrec, RECTYPE_UID );
 
-                   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 */
+       if( !(uidrec.r.uid.uidflags & UIDF_CHECKED) )
+           continue; /* user id has not been checked */
+       if( !(uidrec.r.uid.uidflags & UIDF_VALID) )
+           continue; /* user id is not valid */
+       if( (uidrec.r.uid.uidflags & UIDF_REVOKED) )
+           continue; /* user id has been revoked */
 
-       /* delete this hlst record */
-       hlst_rn = hlstrec.r.hlst.next;
-       delete_record( hlstrec.recnum );
-    } /* loop over hintlist */
-}
+       /* loop over all signature records */
+       for(sigrno=uidrec.r.uid.siglist; sigrno; sigrno = sigrec.r.sig.next ) {
+           int i;
+           TN tn;
 
+           read_record( sigrno, &sigrec, RECTYPE_SIG );
 
-/****************
- * 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;
+           for(i=0; i < SIGS_PER_RECORD; i++ ) {
+               if( !sigrec.r.sig.sig[i].lid )
+                   continue; /* skip deleted sigs */
+               if( !(sigrec.r.sig.sig[i].flag & SIGF_CHECKED) )
+                   continue; /* skip unchecked signatures */
+               if( !(sigrec.r.sig.sig[i].flag & SIGF_VALID) )
+                   continue; /* skip invalid signatures */
+               if( (sigrec.r.sig.sig[i].flag & SIGF_EXPIRED) )
+                   continue; /* skip expired signatures */
+               if( (sigrec.r.sig.sig[i].flag & SIGF_REVOKED) )
+                   continue; /* skip revoked signatures */
+               /* check for cycles */
+               for( tn=keynode; tn && tn->lid != sigrec.r.sig.sig[i].lid;
+                                                         tn = tn->back )
+                   ;
+               if( tn )
+                   continue; /* cycle found */
 
-    /* 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;
+               tn = build_cert_tree( sigrec.r.sig.sig[i].lid,
+                                     depth+1, max_depth, helproot );
+               if( !tn )
+                   continue; /* cert chain too deep or error */
+
+               if( !uidnode ) {
+                   uidnode = new_tn();
+                   uidnode->back = keynode;
+                   uidnode->lid = uidrno;
+                   uidnode->is_uid = 1;
+                   uidnode->next = keynode->list;
+                   keynode->list = uidnode;
+               }
+
+               tn->back = uidnode;
+               tn->next = uidnode->list;
+               uidnode->list = tn;
+             #if 0 /* optimazation - fixme: reenable this later */
+               if( tn->n.k.buckstop ) {
+                   /* ultimately trusted key found:
+                    * no need to check more signatures of this uid */
+                   sigrec.r.sig.next = 0;
+                   break;
                }
+             #endif
            }
-           else if( hlst.r.hlst.rnum[i] == lid )
-               return newlid; /* the signature is already in the hintlist */
-       }
-    }
-    /* 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 );
+       } /* end loop over sig recs */
+    } /* end loop over user ids */
+
+    if( !keynode->list ) {
+       release_tn_tree( keynode );
+       keynode = NULL;
     }
 
-    return newlid;
+    return keynode;
 }
 
 
-/****************
- * 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 )
+propagate_validity( TN node )
 {
-    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;
-
-    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;
-    }
-    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;
-       }
-    }
+    TN kr, ur;
+    int max_validity = 0;
 
-    if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) )
+    assert( !node->is_uid );
+    if( node->n.k.ownertrust == TRUST_ULTIMATE ) {
+       /* this is one of our keys */
+       assert( !node->list ); /* it should be a leaf */
+       node->n.k.validity = TRUST_ULTIMATE;
        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;
+    /* loop over all user ids */
+    for( ur=node->list; ur; ur = ur->next ) {
+       assert( ur->is_uid );
+       /* loop over all signators */
+       for(kr=ur->list; kr; kr = kr->next ) {
+           propagate_validity( kr );
+           if( kr->n.k.validity == TRUST_ULTIMATE ) {
+               ur->n.u.fully_count = opt.completes_needed;
+           }
+           else if( kr->n.k.validity == TRUST_FULLY ) {
+               if( kr->n.k.ownertrust == TRUST_FULLY )
+                   ur->n.u.fully_count++;
+               else if( kr->n.k.ownertrust == TRUST_MARGINAL )
+                   ur->n.u.marginal_count++;
+           }
+       }
+       /* fixme: We can move this test into the loop to stop as soon as
+        * we have a level of FULLY and return from this function
+        * We dont do this now to get better debug output */
+       if( ur->n.u.fully_count >= opt.completes_needed
+           || ur->n.u.marginal_count >= opt.marginals_needed )
+           ur->n.u.validity = TRUST_FULLY;
+       else if( ur->n.u.fully_count || ur->n.u.marginal_count )
+           ur->n.u.validity = TRUST_MARGINAL;
+
+       if( ur->n.u.validity >= max_validity )
+           max_validity = ur->n.u.validity;
     }
 
-    for( node=keynode->next; node; node = node->next ) {
-       PKT_signature *sig;
+    node->n.k.validity = max_validity;
+}
 
-       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) );
+/****************
+ * Given the directory record of a key, check whether we can
+ * find a path to an ultimately trusted key.  We do this by
+ * checking all key signatures up to a some depth.
+ */
+static int
+verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
+{
+    TN tree;
+    int keytrust;
+
+    tree = build_cert_tree( drec->r.dir.lid, 0, opt.max_cert_depth, NULL );
+    if( !tree )
+       return TRUST_UNDEFINED;
+    propagate_validity( tree );
+    if( namehash ) {
+       /* find the matching user id.
+        * fixme: the way we handle this is too inefficient */
+       TN ur;
+       TRUSTREC rec;
+
+       keytrust = 0;
+       for( ur=tree->list; ur; ur = ur->next ) {
+           read_record( ur->lid, &rec, RECTYPE_UID );
+           if( !memcmp( namehash, rec.r.uid.namehash, 20 ) ) {
+               keytrust = ur->n.u.validity;
+               break;
            }
-           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) );
+    }
+    else
+       keytrust = tree->n.k.validity;
+
+    /* update the cached validity values */
+    if( keytrust >= TRUST_UNDEFINED
+       && tdbio_db_matches_options()
+       && ( !drec->r.dir.valcheck || drec->r.dir.validity != keytrust ) ) {
+       TN ur;
+       TRUSTREC rec;
+
+       for( ur=tree->list; ur; ur = ur->next ) {
+           read_record( ur->lid, &rec, RECTYPE_UID );
+           if( rec.r.uid.validity != ur->n.u.validity ) {
+               rec.r.uid.validity = ur->n.u.validity;
+               write_record( &rec );
            }
-           revoke_seen = 1;
        }
+
+       drec->r.dir.validity = tree->n.k.validity;
+       drec->r.dir.valcheck = make_timestamp();
+       write_record( drec );
+       do_sync();
     }
 
-    write_record( &krec );
+    release_tn_tree( tree );
+    return keytrust;
 }
 
 
 /****************
- * 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.
+ * we have the pubkey record and all needed informations are in the trustdb
+ * but nothing more is known.
  */
-static void
-upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
-               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
+static int
+do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
 {
-    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;
-
-    if( DBG_TRUST )
-       log_debug("upd_uid_record for %08lX/%02X%02X\n",
-                              (ulong)keyid[1], uidhash[18], uidhash[19]);
-
-    /* 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 );
+    if( !dr->r.dir.keylist ) {
+       log_error(_("Ooops, no keys\n"));
+       return G10ERR_TRUSTDB;
     }
-    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( !dr->r.dir.uidlist ) {
+       log_error(_("Ooops, no user ids\n"));
+       return G10ERR_TRUSTDB;
     }
 
-    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;
+    if( namehash ) {
+       /* Fixme: use the cache */
+       *validity = verify_key( opt.max_cert_depth, dr, namehash );
+    }
+    else if( tdbio_db_matches_options()
+       && dr->r.dir.valcheck
+           > tdbio_read_modify_stamp( (dr->r.dir.validity < TRUST_FULLY) )
+       && dr->r.dir.validity )
+       *validity = dr->r.dir.validity;
+    else
+       *validity = verify_key( opt.max_cert_depth, dr, NULL );
 
-           sig = node->pkt->pkt.signature;
+    if( dr->r.dir.dirflags & DIRF_REVOKED )
+       *validity |= TRUST_FLAG_REVOKED;
 
-           if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
-               continue; /* not a self signature */
+    return 0;
+}
 
-           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 */
 
+\f
+/***********************************************
+ *********  Change trustdb values **************
+ ***********************************************/
 
-    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 */
+int
+update_ownertrust( ulong lid, unsigned new_trust )
+{
+    TRUSTREC rec;
 
-    /* check the preferences */
-    if( selfsig )
-       upd_pref_record( &urec, keyid, selfsig );
+    init_trustdb();
+    read_record( lid, &rec, RECTYPE_DIR );
+    rec.r.dir.ownertrust = new_trust;
+    write_record( &rec );
+    do_sync();
+    return 0;
+}
 
-    /* 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;
+int
+clear_trust_checked_flag( PKT_public_key *pk )
+{
+    TRUSTREC rec;
+    int rc;
 
-       sig = node->pkt->pkt.signature;
+    if( opt.dry_run )
+       return 0;
 
-       if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] )
-           continue; /* skip self signature */
+    init_trustdb();
+    rc = get_dir_record( pk, &rec );
+    if( rc )
+       return rc;
 
-       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 */
+    /* check whether they are already reset */
+    if( !(rec.r.dir.dirflags & DIRF_CHECKED) && !rec.r.dir.valcheck )
+       return 0;
 
-    write_record( &urec );
+    /* reset the flag */
+    rec.r.dir.dirflags &= ~DIRF_CHECKED;
+    rec.r.dir.valcheck = 0;
+    write_record( &rec );
+    do_sync();
+    return 0;
 }
 
 
-
 /****************
- *
- *
+ * Put new entries  from the pubrings into the trustdb.
+ * This function honors the sig flags to speed up the check.
  */
-static void
-upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
+void
+update_trustdb( )
 {
-    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;
+    KBNODE keyblock = NULL;
+    KBPOS kbpos;
+    int rc;
 
-    if( DBG_TRUST )
-       log_debug("upd_pref_record for %08lX.%lu/%02X%02X\n",
-                         (ulong)keyid[1], lid, uidhash[18], uidhash[19] );
+    if( opt.dry_run )
+       return;
+
+    init_trustdb();
+    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;
 
-    /* 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;
+           rc = update_trust_record( keyblock, 1, &modified );
+           if( rc == -1 ) { /* not yet in trustdb: insert */
+               PKT_public_key *pk = keyblock->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++;
                }
-               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;
+           else if( rc ) {
+               log_error(_("lid %lu: update failed: %s\n"),
+                        lid_from_keyblock(keyblock), g10_errstr(rc) );
+               err_count++;
            }
-           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];
+           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) );
+
+           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( n_prefs_sig == n_prefs_rec
-       && !memcmp( prefs_sig, prefs_rec, n_prefs_sig ) )
-       return;  /* not changed */
+    if( rc && rc != -1 )
+       log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
 
-    /* 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 );
+    enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+    release_kbnode( keyblock );
+}
+
+/****************
+ * 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];
+
+    init_trustdb();
+    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;
 
-    if( n_prefs_sig > ITEMS_PER_PREF_RECORD )
-        log_info(_("WARNING: can't yet handle long pref records\n"));
+       for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
+           if( rec.rectype == RECTYPE_DIR ) {
+               TRUSTREC tmp;
+               int modified;
 
-    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;
-       byte *pp = prefs_sig;
+               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 );
 
-       n = n_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();
+               release_kbnode( keyblock ); keyblock = NULL;
+               if( !(++count % 100) )
+                   log_info(_("%lu keys so far processed\n"), count);
            }
-           write_record( &tmp );
-       } while( n );
+       }
+       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);
     }
-    write_record( &prec );
-    urec->r.uid.prefrec = prec.recnum;
-    urec->dirty = 1;
 }
 
 
+\f
+/***********************************************
+ *********  Query trustdb values  **************
+ ***********************************************/
+
 
-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 revoked )
+/****************
+ * This function simply looks for the key in the trustdb
+ * and makes sure that pk->local_id is set to the correct value.
+ * Return: 0 = found
+ *        -1 = not found
+ *       other = error
+ */
+int
+query_trust_record( PKT_public_key *pk )
 {
-    /* 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 the missing public key
-     * gets 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;
+    init_trustdb();
+    return get_dir_record( pk, &rec );
+}
 
 
-    if( DBG_TRUST )
-       log_debug("upd_cert_record for %08lX.?/%02X%02X/%08lX\n",
-                             (ulong)keyid[1], uidhash[18],
-                              uidhash[19], (ulong)sig->keyid[1] );
+/****************
+ * Get the trustlevel for this PK.
+ * Note: This does not ask any questions
+ * Returns: 0 okay of an errorcode
+ *
+ * It operates this way:
+ *  locate the pk in the trustdb
+ *     found:
+ *         Do we have a valid cache record for it?
+ *             yes: return trustlevel from cache
+ *             no:  make a cache record and all the other stuff
+ *     not found:
+ *         try to insert the pubkey into the trustdb and check again
+ *
+ * Problems: How do we get the complete keyblock to check that the
+ *          cache record is actually valid?  Think we need a clever
+ *          cache in getkey.c  to keep track of this stuff. Maybe it
+ *          is not necessary to check this if we use a local pubring. Hmmmm.
+ */
+int
+check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte *namehash )
+{
+    TRUSTREC rec;
+    unsigned trustlevel = TRUST_UNKNOWN;
+    int rc=0;
+    u32 cur_time;
+    u32 keyid[2];
 
-    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];
+    init_trustdb();
+    keyid_from_pk( pk, keyid );
 
-               keyid_from_pk( pk, akid );
-               rc = tdbio_search_sdir( akid, pk->pubkey_algo, &rec );
-               if( !rc )
-                   pk_lid = rec.recnum;
+    /* get the pubkey record */
+    if( pk->local_id ) {
+       read_record( pk->local_id, &rec, RECTYPE_DIR );
+    }
+    else { /* no local_id: scan the trustdb */
+       if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 ) {
+           log_error(_("check_trust: search dir record failed: %s\n"),
+                                                           g10_errstr(rc));
+           return rc;
+       }
+       else if( rc == -1 ) { /* not found - insert */
+           rc = insert_trust_record( pk );
+           if( rc ) {
+               log_error(_("key %08lX: insert trust record failed: %s\n"),
+                                         (ulong)keyid[1], g10_errstr(rc));
+               goto leave;
            }
+           log_info(_("key %08lX.%lu: inserted into trustdb\n"),
+                                         (ulong)keyid[1], pk->local_id );
+           /* and re-read the dir record */
+           read_record( pk->local_id, &rec, RECTYPE_DIR );
        }
     }
-    free_public_key( pk ); pk = NULL;
-
-    /* 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 0 /* must take uid into account */
-               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;
-               }
-             #endif
-               found_sig = 1;
-           }
-           if( !recheck && !revoked && (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 */
+    cur_time = make_timestamp();
+    if( pk->timestamp > cur_time ) {
+       log_info(_("key %08lX.%lu: created in future "
+                  "(time warp or clock problem)\n"),
+                                         (ulong)keyid[1], pk->local_id );
+       return G10ERR_TIME_CONFLICT;
+    }
 
-           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],
-                               revoked? _("Valid certificate revocation")
-                                      : _("Good certificate") );
-                   rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
-                   if( revoked )
-                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
-               }
-               else if( rc == G10ERR_NO_PUBKEY ) {
-                   /* 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?") );
-                   rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
-                   if( revoked )
-                       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],
-                               revoked? _("Invalid certificate revocation")
-                                      : _("Invalid certificate"),
-                                                   g10_errstr(rc));
-                   rec.r.sig.sig[i].flag = SIGF_CHECKED;
-                   if( revoked )
-                       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( revoked )
-                       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;
+    if( pk->expiredate && pk->expiredate <= cur_time ) {
+       log_info(_("key %08lX.%lu: expired at %s\n"),
+                       (ulong)keyid[1], pk->local_id,
+                            asctimestamp( pk->expiredate) );
+        trustlevel = TRUST_EXPIRED;
+    }
+    else {
+       rc = do_check( &rec, &trustlevel, namehash );
+       if( rc ) {
+           log_error(_("key %08lX.%lu: trust check failed: %s\n"),
+                           (ulong)keyid[1], pk->local_id, g10_errstr(rc));
+           return rc;
        }
     }
 
-    if( found_sig )  /* fixme: uid stuff */
-       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 );
+  leave:
+    if( DBG_TRUST )
+       log_debug("check_trust() returns trustlevel %04x.\n", trustlevel);
+    *r_trustlevel = trustlevel;
+    return 0;
+}
 
-    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],
-                               revoked? _("Valid certificate revocation")
-                                      : _("Good certificate") );
-       newlid = pk_lid;  /* this is the pk of the signature */
-       newflag = SIGF_CHECKED | SIGF_VALID;
-       if( revoked )
-           newflag |= SIGF_REVOKED;
-    }
-    else if( rc == G10ERR_NO_PUBKEY ) {
-       if( opt.verbose > 1 || DBG_TRUST )
-           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( revoked )
-           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],
-               revoked? _("Invalid certificate revocation")
-                      : _("Invalid certificate"),
-                                           g10_errstr(rc));
-       newlid = create_shadow_dir( sig, lid );
-       newflag = SIGF_CHECKED;
-       if( revoked )
-           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;
+int
+query_trust_info( PKT_public_key *pk, const byte *namehash )
+{
+    unsigned trustlevel;
+    int c;
 
-       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;
-    }
+    init_trustdb();
+    if( check_trust( pk, &trustlevel, namehash ) )
+       return '?';
+    if( trustlevel & TRUST_FLAG_REVOKED )
+       return 'r';
+    c = trust_letter( (trustlevel & TRUST_MASK) );
+    if( !c )
+       c = '?';
+    return c;
 }
 
 
+
 /****************
- * 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().
+ * Return the assigned ownertrust value for the given LID
  */
-int
-update_trust_record( KBNODE keyblock, int recheck, int *modified )
+unsigned
+get_ownertrust( ulong lid )
 {
-    PKT_public_key *primary_pk;
-    KBNODE node;
-    TRUSTREC drec;
-    TRUSTREC krec;
-    TRUSTREC urec;
-    TRUSTREC prec;
-    TRUSTREC helprec;
-    int rc = 0;
-    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 */
+    TRUSTREC rec;
 
-    if( opt.dry_run )
-       return 0;
+    init_trustdb();
+    read_record( lid, &rec, RECTYPE_DIR );
+    return rec.r.dir.ownertrust;
+}
 
-    INIT_TRUSTDB();
-    if( modified )
-       *modified = 0;
+int
+get_ownertrust_info( ulong lid )
+{
+    unsigned otrust;
+    int c;
 
-    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;
+    init_trustdb();
+    otrust = get_ownertrust( lid );
+    c = trust_letter( (otrust & TRUST_MASK) );
+    if( !c )
+       c = '?';
+    return c;
+}
 
-    keyid_from_pk( primary_pk, keyid );
 
-    /* fixme: check that the keyblock has a valid structure */
 
-    rc = tdbio_begin_transaction();
-    if( rc )
-       return rc;
+void
+list_trust_path( const char *username )
+{
+    int rc;
+    ulong lid;
+    TRUSTREC rec;
+    TN tree;
+    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
 
-    /* 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 );
+    init_trustdb();
+    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 );
+       }
     }
+    lid = pk->local_id;
 
-    /* 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;
-           }
-       }
+    tree = build_cert_tree( lid, 0, opt.max_cert_depth, NULL );
+    if( tree )
+       propagate_validity( tree );
+    dump_tn_tree( 0, tree );
+    printf("(alloced tns=%d  max=%d)\n", alloced_tns, max_alloced_tns );
+    release_tn_tree( tree );
+    printf("Ownertrust=%c Validity=%c\n", get_ownertrust_info( lid ),
+                                         query_trust_info( pk, NULL ) );
 
-       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 );
+    free_public_key( pk );
+
+}
+
+
+
+
+/****************
+ * Enumerate all keys, which are needed to build all trust paths for
+ * the given key.  This function does not return the key itself or
+ * the ultimate key (the last point in cerificate chain).  Only
+ * certificate chains which ends up at an ultimately trusted key
+ * are listed. If ownertrust or validity is not NULL, the corresponding
+ * value for the returned LID is also returned in these variable(s).
+ *
+ *  1) create a void pointer and initialize it to NULL
+ *  2) pass this void pointer by reference to this function.
+ *     Set lid to the key you want to enumerate and pass it by reference.
+ *  3) call this function as long as it does not return -1
+ *     to indicate EOF. LID does contain the next key used to build the web
+ *  4) Always call this function a last time with LID set to NULL,
+ *     so that it can free its context.
+ *
+ * Returns: -1 on EOF or the level of the returned LID
+ */
+int
+enum_cert_paths( void **context, ulong *lid,
+                unsigned *ownertrust, unsigned *validity )
+{
+    return -1;
+  #if 0
+    struct enum_cert_paths_ctx *ctx;
+    fixme: .....   tsl;
+
+    init_trustdb();
+    if( !lid ) {  /* release the context */
+       if( *context ) {
+           FIXME: ........tsl2;
+
+           ctx = *context;
+           for(tsl = ctx->tsl_head; tsl; tsl = tsl2 ) {
+               tsl2 = tsl->next;
+               m_free( tsl );
            }
-           delete_record( recno );
+           *context = NULL;
        }
-       else
-           lastrecno = recno;
+       return -1;
     }
 
+    if( !*context ) {
+       FIXME .... *tmppath;
+       TRUSTREC rec;
 
+       if( !*lid )
+           return -1;
 
-    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();
+       ctx = m_alloc_clear( sizeof *ctx );
+       *context = ctx;
+       /* collect the paths */
+      #if 0
+       read_record( *lid, &rec, RECTYPE_DIR );
+       tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
+       tsl = NULL;
+       collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &tsl );
+       m_free( tmppath );
+       sort_tsl_list( &tsl );
+      #endif
+       /* setup the context */
+       ctx->tsl_head = tsl;
+       ctx->tsl = ctx->tsl_head;
+       ctx->idx = 0;
     }
-    rel_recno_list( &recno_list );
-    return rc;
+    else
+       ctx = *context;
+
+    while( ctx->tsl && ctx->idx >= ctx->tsl->pathlen ) {
+       ctx->tsl = ctx->tsl->next;
+       ctx->idx = 0;
+    }
+    tsl = ctx->tsl;
+    if( !tsl )
+       return -1; /* eof */
+
+    if( ownertrust )
+       *ownertrust = tsl->path[ctx->idx].otrust;
+    if( validity )
+       *validity = tsl->path[ctx->idx].trust;
+    *lid = tsl->path[ctx->idx].lid;
+    ctx->idx++;
+    return ctx->idx-1;
+  #endif
 }
 
 
 /****************
- * Insert a trust record into the TrustDB
- * This function assumes that the record does not yet exist.
+ * Print the current path
  */
-int
-insert_trust_record( PKT_public_key *pk )
+void
+enum_cert_paths_print( void **context, FILE *fp,
+                                      int refresh, ulong selected_lid )
 {
-    TRUSTREC dirrec;
-    TRUSTREC shadow;
-    KBNODE keyblock = NULL;
-    KBNODE node;
-    byte fingerprint[MAX_FINGERPRINT_LEN];
-    size_t fingerlen;
-    int rc = 0;
-    ulong hintlist = 0;
-
-
-    if( opt.dry_run )
-       return 0;
+    return;
+  #if 0
+    struct enum_cert_paths_ctx *ctx;
+    FIXME......... tsl;
 
-    INIT_TRUSTDB();
+    if( !*context )
+       return;
+    init_trustdb();
+    ctx = *context;
+    if( !ctx->tsl )
+       return;
+    tsl = ctx->tsl;
 
-    fingerprint_from_pk( pk, fingerprint, &fingerlen );
+    if( !fp )
+       fp = stderr;
 
-    /* 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.)
-     */
+    if( refresh ) { /* update the ownertrust and if possible the validity */
+       int i;
+       int match = tdbio_db_matches_options();
 
-    /* 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;
-    }
+       for( i = 0; i < tsl->pathlen; i++ )  {
+           TRUSTREC rec;
 
-    if( pk->local_id ) {
-       log_debug("insert_trust_reord with pk->local_id=%lu\n", pk->local_id );
-       rc = update_trust_record( keyblock, 1, NULL );
-       release_kbnode( keyblock );
-       return rc;
+           read_record( tsl->path[i].lid, &rec, RECTYPE_DIR );
+           tsl->path[i].otrust = rec.r.dir.ownertrust;
+           /* update validity only if we have it in the cache
+            * calculation is too time consuming */
+           if( match && rec.r.dir.valcheck && rec.r.dir.validity ) {
+               tsl->path[i].trust = rec.r.dir.validity;
+               if( rec.r.dir.dirflags & DIRF_REVOKED )
+                   tsl->path[i].trust = TRUST_FLAG_REVOKED;
+           }
+       }
     }
 
-    /* check that we used the primary key (we are little bit paranoid) */
-    {  PKT_public_key *a_pk;
-       u32 akid[2], bkid[2];
-
-       node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
-       a_pk = node->pkt->pkt.public_key;
-
-       /* 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 );
+    print_path( tsl->pathlen, tsl->path, fp, selected_lid );
+  #endif
+}
 
-       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 );
+/*
+ * 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 allocated 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;
 
-    /* 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 *a_pk = node->pkt->pkt.public_key;
-           a_pk->local_id = dirrec.r.dir.lid;
-       }
-       else if( node->pkt->pkttype == PKT_SIGNATURE ) {
-           PKT_signature *a_sig = node->pkt->pkt.signature;
-           a_sig->local_id = dirrec.r.dir.lid;
+    init_trustdb();
+    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;
        }
     }
-
-    /* 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;
+    return NULL;
 }
 
 
+
+/****************
+ * Check whether the algorithm is in one of the pref records
+ */
 int
-update_ownertrust( ulong lid, unsigned new_trust )
+is_algo_in_prefs( ulong lid, int preftype, int algo )
 {
     TRUSTREC rec;
+    ulong recno;
+    int i;
+    byte *pref;
 
-    INIT_TRUSTDB();
+    init_trustdb();
     read_record( lid, &rec, RECTYPE_DIR );
-    rec.r.dir.ownertrust = new_trust;
-    write_record( &rec );
-    do_sync();
+    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;
 }
 
-
index 303ffc7..dba9e5c 100644 (file)
 
 
 /*-- trustdb.c --*/
-void list_trustdb(const char *username);
 void list_trust_path( const char *username );
-void export_ownertrust(void);
-void import_ownertrust(const char *fname);
 void register_trusted_key( const char *string );
 void check_trustdb( const char *username );
 void update_trustdb( void );
-int init_trustdb( int level, const char *dbname );
+int setup_trustdb( int level, const char *dbname );
+void init_trustdb( void );
 int check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte* nh );
 int query_trust_info( PKT_public_key *pk, const byte *nh );
 int enum_cert_paths( void **context, ulong *lid,
@@ -66,6 +64,12 @@ int clear_trust_checked_flag( PKT_public_key *pk );
 int insert_trust_record( PKT_public_key *pk );
 int update_trust_record( KBNODE keyblock, int fast, int *modified );
 int update_ownertrust( ulong lid, unsigned new_trust );
+int trust_letter( unsigned value );
+
+/*-- tdbdump.c --*/
+void list_trustdb(const char *username);
+void export_ownertrust(void);
+void import_ownertrust(const char *fname);
 
 /*-- pkclist.c --*/
 int edit_ownertrust( ulong lid, int mode );
index 804b73f..1312732 100644 (file)
@@ -7,6 +7,4 @@ missing
 gnupg.spec.in
 autogen.sh
 ChangeLog
-ltconfig
-ltmain.sh