See ChangeLog: Wed Mar 17 13:09:03 CET 1999 Werner Koch
authorWerner Koch <wk@gnupg.org>
Wed, 17 Mar 1999 12:13:04 +0000 (12:13 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 17 Mar 1999 12:13:04 +0000 (12:13 +0000)
27 files changed:
NEWS
TODO
acinclude.m4
checks/ChangeLog
checks/genkey1024.test
checks/mds.test
cipher/ChangeLog
cipher/rndegd.c
configure.in
doc/DETAILS
g10/ChangeLog
g10/armor.c
g10/encode.c
g10/g10.c
g10/getkey.c
g10/keydb.h
g10/mainproc.c
g10/passphrase.c
g10/pkclist.c
g10/seckey-cert.c
g10/status.c
g10/status.h
g10/tdbio.c
g10/tdbio.h
g10/trustdb.c
g10/trustdb.h
include/cipher.h

diff --git a/NEWS b/NEWS
index 15d5d9e..688069e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@
 
     * A bunch of changes to the key validation code.
 
+    * --list-trust-path now has an optional --with-colons format.
+
 
 Noteworthy changes in version 0.9.4
 -----------------------------------
diff --git a/TODO b/TODO
index 9833173..0e35c6c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,17 +1,14 @@
 
-  * Replace --trusted-keys by a local certificate (which does not get
-    exported).
-
   * add some status output put for signing and encryption.
-    replace the puc in primegen with some kind of status-fd outputs.
+    replace the putc in primegen with some kind of status-fd outputs.
 
   * Finish the EGD module.
 
-  * Implement 256 bit key Twofish (wait until the 2nd AES conference).
+  * Implement 256 bit key Twofish.
 
-  * Check revocation and expire stuff. [I'm currently working on this.]
+  * Check revocation and expire stuff.
 
-  * Check calculation of key validity. [I'm currently working on this.]
+  * Check calculation of key validity.
 
   * See why we always get this "Hmmm public key lost"
 
   * when decryptiong multiple key: print a warning only if no usable pubkey
     encrypt package was found. Extension: display a list of all recipients.
 
-* an ERRSIG argument like
-  ERRSIG <keyid>, where <keyid> is the id of the missing public key
-    or a new keyword
-  PUBLIC_MISSING <keyid>
-* a status line complaining about a missing secret key like
-  SECRET_MISSING <keyid>, where <keyid> is the id of the missing secret key
-* a status line complaining about a bad passphrase like
-  BADPASS
-
-
+  * Add NO_PUBKEY and NO_SECKEY status lines.
+  * Add more NODATA status lines
 
+  * gpg --keyserver wwwkeys.us.pgp.net --importserver 0x12345678
+    (or --importserver warner@lothar.com, etc)
 
 
 Nice to have
index 2349da6..11ba6fd 100644 (file)
@@ -343,4 +343,256 @@ define(GNUPG_CHECK_MLOCK,
   ])
 
 
+################################################################
+
+# GNUPG_PROG_NM - find the path to a BSD-compatible name lister
+AC_DEFUN(GNUPG_PROG_NM,
+[AC_MSG_CHECKING([for BSD-compatible nm])
+AC_CACHE_VAL(ac_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  ac_cv_path_NM="$NM"
+else
+  IFS="${IFS=   }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/nm; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -B"
+      elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -p"
+      else
+        ac_cv_path_NM="$ac_dir/nm"
+      fi
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
+fi])
+NM="$ac_cv_path_NM"
+AC_MSG_RESULT([$NM])
+AC_SUBST(NM)
+])
+
+# GNUPG_SYS_NM_PARSE - Check for command ro grab the raw symbol name followed
+# by C symbol name from nm.
+AC_DEFUN(GNUPG_SYS_NM_PARSE,
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([GNUPG_PROG_NM])dnl
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output])
+AC_CACHE_VAL(ac_cv_sys_global_symbol_pipe,
+[# These are sane defaults that work on at least a few old systems.
+# {They come from Ultrix.  What could be older than Ultrix?!! ;)}
+
+changequote(,)dnl
+# Character class describing NM global symbol codes.
+ac_symcode='[BCDEGRSTU]'
+
+# Regexp to match symbols that can be accessed directly from C.
+ac_sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+ac_symxfrm='\1 \1'
+
+# Define system-specific variables.
+case "$host_os" in
+aix*)
+  ac_symcode='[BCDTU]'
+  ;;
+sunos* | cygwin32* | mingw32*)
+  ac_sympat='_\([_A-Za-z][_A-Za-z0-9]*\)'
+  ac_symxfrm='_\1 \1'
+  ;;
+irix*)
+  # Cannot use undefined symbols on IRIX because inlined functions mess us up.
+  ac_symcode='[BCDEGRST]'
+  ;;
+solaris*)
+  ac_symcode='[BDTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
+  ac_symcode='[ABCDGISTUW]'
+fi
+
+case "$host_os" in
+cygwin32* | mingw32*)
+  # We do not want undefined symbols on cygwin32.  The user must
+  # arrange to define them via -l arguments.
+  ac_symcode='[ABCDGISTW]'
+  ;;
+esac
+changequote([,])dnl
+
+# Write the raw and C identifiers.
+ac_cv_sys_global_symbol_pipe="sed -n -e 's/^.* $ac_symcode $ac_sympat$/$ac_symxfrm/p'"
+
+# Check to see that the pipe works correctly.
+ac_pipe_works=no
+cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func;return 0;}
+EOF
+if AC_TRY_EVAL(ac_compile); then
+  # Now try to grab the symbols.
+  ac_nlist=conftest.nm
+  if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then
+
+    # Try sorting and uniquifying the output.
+    if sort "$ac_nlist" | uniq > "$ac_nlist"T; then
+      mv -f "$ac_nlist"T "$ac_nlist"
+      ac_wcout=`wc "$ac_nlist" 2>/dev/null`
+changequote(,)dnl
+      ac_count=`echo "X$ac_wcout" | sed -e 's,^X,,' -e 's/^[    ]*\([0-9][0-9]*\).*$/\1/'`
+changequote([,])dnl
+      (test "$ac_count" -ge 0) 2>/dev/null || ac_count=-1
+    else
+      rm -f "$ac_nlist"T
+      ac_count=-1
+    fi
+
+    # Make sure that we snagged all the symbols we need.
+    if egrep ' nm_test_var$' "$ac_nlist" >/dev/null; then
+      if egrep ' nm_test_func$' "$ac_nlist" >/dev/null; then
+        cat <<EOF > conftest.c
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+        # Now generate the symbol file.
+        sed 's/^.* \(.*\)$/extern char \1;/' < "$ac_nlist" >> conftest.c
+
+        cat <<EOF >> conftest.c
+#if defined (__STDC__) && __STDC__
+# define __ptr_t void *
+#else
+# define __ptr_t char *
+#endif
+
+/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */
+int dld_preloaded_symbol_count = $ac_count;
+
+/* The mapping between symbol names and symbols. */
+struct {
+  char *name;
+  __ptr_t address;
+}
+changequote(,)dnl
+dld_preloaded_symbols[] =
+changequote([,])dnl
+{
+EOF
+        sed 's/^\(.*\) \(.*\)$/  {"\1", (__ptr_t) \&\2},/' < "$ac_nlist" >> conftest.c
+        cat <<\EOF >> conftest.c
+  {0, (__ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+        # Now try linking the two files.
+        mv conftest.$ac_objext conftestm.$ac_objext
+        ac_save_LIBS="$LIBS"
+        ac_save_CFLAGS="$CFLAGS"
+        LIBS="conftestm.$ac_objext"
+        CFLAGS="$CFLAGS$no_builtin_flag"
+        if AC_TRY_EVAL(ac_link) && test -s conftest; then
+          ac_pipe_works=yes
+        else
+          echo "configure: failed program was:" >&AC_FD_CC
+          cat conftest.c >&AC_FD_CC
+        fi
+        LIBS="$ac_save_LIBS"
+        CFLAGS="$ac_save_CFLAGS"
+      else
+        echo "cannot find nm_test_func in $ac_nlist" >&AC_FD_CC
+      fi
+    else
+      echo "cannot find nm_test_var in $ac_nlist" >&AC_FD_CC
+    fi
+  else
+    echo "cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC
+  fi
+else
+  echo "$progname: failed program was:" >&AC_FD_CC
+  cat conftest.c >&AC_FD_CC
+fi
+rm -rf conftest*
+
+# Do not use the global_symbol_pipe unless it works.
+test "$ac_pipe_works" = yes || ac_cv_sys_global_symbol_pipe=
+])
+
+ac_result=yes
+if test -z "$ac_cv_sys_global_symbol_pipe"; then
+   ac_result=no
+fi
+AC_MSG_RESULT($ac_result)
+])
+
+# GNUPG_SYS_LIBTOOL_CYGWIN32 - find tools needed on cygwin32
+AC_DEFUN(GNUPG_SYS_LIBTOOL_CYGWIN32,
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+AC_CHECK_TOOL(AS, as, false)
+])
+
+# GNUPG_SYS_SYMBOL_UNDERSCORE - does the compiler prefix global symbols
+#                            with an underscore?
+AC_DEFUN(GNUPG_SYS_SYMBOL_UNDERSCORE,
+[AC_REQUIRE([GNUPG_PROG_NM])dnl
+AC_REQUIRE([GNUPG_SYS_NM_PARSE])dnl
+AC_MSG_CHECKING([for _ prefix in compiled symbols])
+AC_CACHE_VAL(ac_cv_sys_symbol_underscore,
+[ac_cv_sys_symbol_underscore=no
+cat > conftest.$ac_ext <<EOF
+void nm_test_func(){}
+int main(){nm_test_func;return 0;}
+EOF
+if AC_TRY_EVAL(ac_compile); then
+  # Now try to grab the symbols.
+  ac_nlist=conftest.nm
+  if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then
+    # See whether the symbols have a leading underscore.
+    if egrep '^_nm_test_func' "$ac_nlist" >/dev/null; then
+      ac_cv_sys_symbol_underscore=yes
+    else
+      if egrep '^nm_test_func ' "$ac_nlist" >/dev/null; then
+        :
+      else
+        echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC
+      fi
+    fi
+  else
+    echo "configure: cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC
+  fi
+else
+  echo "configure: failed program was:" >&AC_FD_CC
+  cat conftest.c >&AC_FD_CC
+fi
+rm -rf conftest*
+])
+AC_MSG_RESULT($ac_cv_sys_symbol_underscore)
+if test x$ac_cv_sys_symbol_underscore = xyes; then
+  AC_DEFINE(WITH_SYMBOL_UNDERSCORE,1,
+  [define if compiled symbols have a leading underscore])
+fi
+])
+
+
 dnl *-*wedit:notab*-*  Please keep this as the last line.
index 27397c0..3217d41 100644 (file)
@@ -1,3 +1,7 @@
+Wed Mar 17 13:09:03 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * mds.test: replaced the "echo -n"
+
 Mon Mar  8 20:47:17 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * pubdemo.asc, secdemo.asc: New.
index ac1868e..bd79bcb 100755 (executable)
@@ -13,7 +13,7 @@ fi
 LANG=
 LANGUAGE=
 
-expect - <<EOF >/dev/null
+expect  - <<EOF >/dev/null
 #set timeout -1
 set timeout 8
 match_max 100000
@@ -89,10 +89,11 @@ Enter passphrase: " { sleep 1; send -- "abc\r" }
 expect {
   -ex "\r                  \rRepeat passphrase: " { sleep 1; send -- "abc\r" }
     timeout { exit 1 } }
+set timeout 600
 expect {
   -ex "\r                   \rWe need to generate a lot of random bytes. It is a good idea to perform\r
 some other action (work in another window, move the mouse, utilize the\r
-network and the disks) during the prime generation; this gives the random\r
+the disks) during the prime generation; this gives the random\r
 number generator a better chance to gain enough entropy.\r" {}
     timeout { exit 1 } }
 set timeout 600
index 2d04812..63bec7c 100755 (executable)
@@ -13,7 +13,7 @@ test_one () {
 failed=""
 
 #info Checking message digests
-echo -n "" | $srcdir/run-gpgm -v --print-mds >y
+cat /dev/null | $srcdir/run-gpgm -v --print-mds >y
 test_one "MD5"    "D41D8CD98F00B204E9800998ECF8427E"
 test_one "SHA1"   "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
 test_one "RMD160" "9C1185A5C5E9FC54612808977EE8F548B2258D31"
@@ -25,7 +25,7 @@ fi
 
 [ "$failed" != "" ] && error "$failed failed for empty string"
 
-echo -n "abcdefghijklmnopqrstuvwxyz" | $srcdir/run-gpgm --print-mds >y
+/bin/echo "abcdefghijklmnopqrstuvwxyz\c" | $srcdir/run-gpgm --print-mds >y
 test_one "MD5"    "C3FCD3D76192E4007DFB496CCA67E13B"
 test_one "SHA1"   "32D10C7B8CF96570CA04CE37F2A19D84240D3A89"
 test_one "RMD160" "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC"
index a9a720f..3ac7d31 100644 (file)
@@ -1,3 +1,8 @@
+Wed Mar 17 13:09:03 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * rndegd.c (do_read): New.
+       (gather_random): Changed the implementation.
+
 Mon Mar  8 20:47:17 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * dynload.c (DLSYM_NEEDS_UNDERSCORE): Renamed.
index 6cdc4dd..0777ff8 100644 (file)
@@ -34,6 +34,7 @@
 #include "util.h"
 #include "ttyio.h"
 #include "dynload.h"
+#include "cipher.h"
 
 #ifdef IS_MODULE
   #define _(a) (a)
@@ -64,18 +65,47 @@ do_write( int fd, void *buf, size_t nbytes )
     return 0;
 }
 
+static int
+do_read( int fd, void *buf, size_t nbytes )
+{
+    int n, nread = 0;
 
+    do {
+       do {
+           n = read(fd, (char*)buf + nread, nbytes );
+       } while( n == -1 && errno == EINTR );
+       if( n == -1 )
+           return -1;
+       nread += n;
+    } while( nread < nbytes );
+    return nbytes;
+}
+
+
+/* fixme: level 1 is not yet handled */
 static int
 gather_random( void (*add)(const void*, size_t, int), int requester,
                                          size_t length, int level )
 {
     static int fd = -1;
     int n;
-    int warn=0;
     byte buffer[256+2];
+    int nbytes;
+    int do_restart = 0;
+
+    if( !length )
+       return 0;
+
 
+  restart:
+    if( do_restart ) {
+       if( fd != -1 ) {
+           close( fd );
+           fd = -1;
+       }
+    }
     if( fd == -1 ) {
-       const char *name = "/tmp/entropy";
+       char *name = make_filename( g10_opt_homedir, "entropy", NULL );
        struct sockaddr_un addr;
        int addr_len;
 
@@ -92,73 +122,63 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
        if( connect( fd, (struct sockaddr*)&addr, addr_len) == -1 )
            g10_log_fatal("can't connect to `%s': %s\n",
                                                    name, strerror(errno) );
+       m_free(name);
+    }
+    do_restart = 0;
+
+    nbytes = length < 255? length : 255;
+    /* first time we do it with a non blocking request */
+    buffer[0] = 1; /* non blocking */
+    buffer[1] = nbytes;
+    if( do_write( fd, buffer, 2 ) == -1 )
+       g10_log_fatal("can't write to the EGD: %s\n", strerror(errno) );
+    n = do_read( fd, buffer, 1 );
+    if( n == -1 ) {
+       g10_log_error("read error on EGD: %s\n", strerror(errno));
+       do_restart = 1;
+       goto restart;
+    }
+    if( !n ) {
+       g10_log_error("bad EGD reply: too short\n");
+       do_restart = 1;
+       goto restart;
+    }
+    if( n > 1 ) {
+       n--;
+       (*add)( buffer+1, n, requester );
+       length -= n;
     }
 
-
+    if( length ) {
+      #ifdef IS_MODULE
+       fprintf( stderr,
+      #else
+       tty_printf(
+      #endif
+        _("Please wait, entropy is being gathered. Do some work if it would\n"
+          "keep you from getting bored, because it will improve the quality\n"
+          "of the entropy.\n") );
+    }
     while( length ) {
-       fd_set rfds;
-       struct timeval tv;
-       int rc;
-       int nbytes;
-       int cmd;
-
        nbytes = length < 255? length : 255;
-       /* send request */
-       cmd = level >= 2 ? 2 : 1;
-       buffer[0] = cmd;
+
+       buffer[0] = 2; /* blocking */
        buffer[1] = nbytes;
        if( do_write( fd, buffer, 2 ) == -1 )
            g10_log_fatal("can't write to the EGD: %s\n", strerror(errno) );
-       /* wait on reply */
-       FD_ZERO(&rfds);
-       FD_SET(fd, &rfds);
-       tv.tv_sec = 3;
-       tv.tv_usec = 0;
-       if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) {
-           if( !warn )
-             #ifdef IS_MODULE
-               fprintf( stderr,
-             #else
-               tty_printf(
-             #endif
-                           _(
-"\n"
-"Not enough random bytes available.  Please do some other work to give\n"
-"the OS a chance to collect more entropy! (Need %d more bytes)\n"), length );
-           warn = 1;
-           continue;
-       }
-       else if( rc == -1 ) {
-           g10_log_error("select error on EGD: %s\n", strerror(errno));
-           continue;
-       }
-
-       /* collect reply */
-       do {
-           n = read(fd, buffer, nbytes+2 );
-       } while( n == -1 && errno == EINTR );
-       /* process reply */
-       if( n == -1 )
+       n = do_read( fd, buffer, nbytes );
+       if( n == -1 ) {
            g10_log_error("read error on EGD: %s\n", strerror(errno));
-       else if( cmd == 2 && n != nbytes  ) {
-           g10_log_error("bad EGD reply: too short %d/%d\n", nbytes, n );
-       }
-       else if( cmd == 2 ) {
-           (*add)( buffer, n, requester );
-           length -= n;
+           do_restart = 1;
+           goto restart;
        }
-       else if( !n )
-           g10_log_error("bad EGD reply: too short\n");
-       else if( buffer[0] != n-1 )
-           g10_log_error("bad EGD reply: count mismatch %d/%d\n",
-                                                     n-1, buffer[0] );
-       else if( n==1 )
-           g10_log_info("no data from EGD\n");
-       else {
-           n -= 1;
-           (*add)( buffer+1, n, requester );
-           length -= n;
+       if( n != nbytes  ) {
+           g10_log_error("bad EGD reply: too short %d/%d\n", nbytes, n );
+           do_restart = 1;
+           goto restart;
        }
+       (*add)( buffer, n, requester );
+       length -= n;
     }
     memset(buffer, 0, sizeof(buffer) );
 
index 1e71eb7..e4760fb 100644 (file)
@@ -28,11 +28,11 @@ dnl
 dnl  Check for random module options
 dnl
 dnl  Fixme: get the list of available modules from MODULES_IN_CIPHER
-dnl         and check agiants this list
+dnl         and check against this list
 
 AC_MSG_CHECKING([which static random module to use])
 AC_ARG_ENABLE(static-rnd,
-    [  --enable-static-rnd=[egd|unix|linux|nonde]  ],
+    [  --enable-static-rnd=[egd|unix|linux|none]  ],
 [use_static_rnd=$enableval], [use_static_rnd=default] )
 
 if test "$use_static_rnd" = no; then
@@ -169,7 +169,7 @@ case "${target}" in
 esac
 
 AC_SUBST(MPI_OPT_FLAGS)
-AM_SYS_SYMBOL_UNDERSCORE
+GNUPG_SYS_SYMBOL_UNDERSCORE
 GNUPG_CHECK_PIC
 GNUPG_CHECK_RDYNAMIC
 if test "$NO_PIC" = yes; then
index 81b9dce..fb26c2b 100644 (file)
@@ -54,10 +54,9 @@ more arguments in future versions.
     BADSIG     <long keyid>  <username>
        The signature with the keyid has not been verified okay.
 
-    ERRSIG
+    ERRSIG  <long keyid>  <algorithm_number>
        It was not possible to check the signature.  This may be
        caused by a missing public key or an unsupported algorithm.
-       No argument yet.
 
     VALIDSIG   <fingerprint in hex>
        The signature with the keyid is good. This is the same
@@ -72,6 +71,13 @@ more arguments in future versions.
        unique ids - others may yield duplicated ones when they
        have been created in the same second.
 
+    ENC_TO  <long keyid>
+       The message is encrypted to this keyid.
+
+    NODATA  <what>
+       No data has been found. Codes for what are:
+           1 - No armored data.
+
     TRUST_UNDEFINED
     TRUST_NEVER
     TRUST_MARGINAL
@@ -98,10 +104,16 @@ more arguments in future versions.
     SHM_GET
     SHM_GET_BOOL
     SHM_GET_HIDDEN
-    NEED_PASSPHRASE
-       [Needs documentation]
 
+    NEED_PASSPHRASE <long keyid>
+       Issued whenever a passphrase is needed.
+
+    BAD_PASSPHRASE <long keyid>
+       The supplied passphrase was wrong
 
+    NO_PUBKEY  <long keyid>
+    NO_SECKEY  <long keyid>
+       The key is not available
 
 
 Key generation
@@ -282,31 +294,6 @@ Record type 8: (shadow directory 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.
-
-     1 byte   value 9
-     1 byte   reserved
-     1 u32    Local-Id.
-     8 bytes  keyid of the primary key (needed?)
-     1 byte   cache-is-valid the following stuff is only
-             valid if this is set.
-     1 byte   reserved
-     20 bytes rmd160 hash value over the complete keyblock
-             This is used to detect any changes of the keyblock with all
-             CTBs and lengths headers. Calculation is easy if the keyblock
-             is obtained from a keyserver: simply create the hash from all
-             received data bytes.
-
-     1 byte   number of untrusted signatures.
-     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  (see trustdb.h)
-
-
 Record Type 10 (hash table)
 --------------
     Due to the fact that we use fingerprints to lookup keys, we can
index 2e682f3..ea1133c 100644 (file)
@@ -1,3 +1,31 @@
+Wed Mar 17 13:09:03 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * trustdb.c (check_trust): add new arg add_fnc and changed all callers.
+       (do_check): Ditto.
+       (verify_key): Ditto.
+       (propagate_validity): Use the new add_fnc arg.
+       (print_user_id): Add the FILE arg.
+       (propagate_ownertrust): New.
+       * pkclist.c (add_ownertrust_cb): New and changed the add_ownertrust
+       logic.
+
+       * getkey.c (get_keyblock_bylid): New.
+       * trustdb.c (print_uid_from_keyblock): New.
+       (dump_tn_tree_with_colons): New.
+       (list_trust_path): Add colon print mode.
+
+       * trustdb.c (insert_trust_record): Always use the primary key.
+
+       * encode.c (encode_simple): Added text_mode filter (RĂ©mi Guyomarch)
+       (encode_crypt): Ditto.
+
+       * mainproc.c (proc_pubkey_enc): Added status ENC_TO.
+       * armor.c (armor_filter): Added status NODATA.
+       * passphrase.c (passphrase_to_dek): Always print NEED_PASSPHRASE
+       * seckey_cert.c (check_secret_key): Added BAD_PASS status.
+
+       * g10.c (main): Set g10_opt_homedir.
+
 Sun Mar 14 19:34:36 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * keygen.c (do_create): Changed wording of the note (Hugh Daniel)
index 1a3e6e5..a6daf71 100644 (file)
@@ -989,8 +989,10 @@ armor_filter( void *opaque, int control,
            iobuf_writestr(a, tail_strings[afx->what] );
            iobuf_writestr(a, "-----\n");
        }
-       else if( !afx->any_data && !afx->inp_bypass )
+       else if( !afx->any_data && !afx->inp_bypass ) {
            log_error(_("no valid OpenPGP data found.\n"));
+           write_status_text( STATUS_NODATA, "1" );
+       }
        if( afx->truncated )
            log_info(_("invalid armor: line longer than %d characters\n"),
                      MAX_LINELEN );
index aba251a..825a4c9 100644 (file)
@@ -76,11 +76,13 @@ encode_simple( const char *filename, int mode )
     cipher_filter_context_t cfx;
     armor_filter_context_t afx;
     compress_filter_context_t zfx;
+    text_filter_context_t tfx;
     int do_compress = opt.compress && !opt.rfc1991;
 
     memset( &cfx, 0, sizeof cfx);
     memset( &afx, 0, sizeof afx);
     memset( &zfx, 0, sizeof zfx);
+    memset( &tfx, 0, sizeof tfx);
     init_packet(&pkt);
 
     /* prepare iobufs */
@@ -90,6 +92,9 @@ encode_simple( const char *filename, int mode )
        return G10ERR_OPEN_FILE;
     }
 
+    if( opt.textmode )
+       iobuf_push_filter( inp, text_filter, &tfx );
+
     cfx.dek = NULL;
     if( mode ) {
        s2k = m_alloc_clear( sizeof *s2k );
@@ -151,19 +156,19 @@ encode_simple( const char *filename, int mode )
        pt->namelen = 0;
     }
     /* pgp5 has problems to decrypt symmetrically encrypted data from
-     * GnuPOG if the filelength is in the inner packet.  It works
+     * GnuPG if the filelength is in the inner packet. It works
      * when only partial length headers are use.  Until we have
      * tracked this problem down. We use this temporary fix
      * (fixme: remove the && !mode )
      */
-    if( filename && !mode ) {
+    if( filename && !opt.textmode && !mode ) {
        if( !(filesize = iobuf_get_filelength(inp)) )
            log_info(_("%s: WARNING: empty file\n"), filename );
     }
     else
        filesize = 0; /* stdin */
     pt->timestamp = make_timestamp();
-    pt->mode = 'b';
+    pt->mode = opt.textmode? 't' : 'b';
     pt->len = filesize;
     pt->buf = inp;
     pkt.pkttype = PKT_PLAINTEXT;
@@ -206,12 +211,14 @@ encode_crypt( const char *filename, STRLIST remusr )
     cipher_filter_context_t cfx;
     armor_filter_context_t afx;
     compress_filter_context_t zfx;
+    text_filter_context_t tfx;
     PK_LIST pk_list;
     int do_compress = opt.compress && !opt.rfc1991;
 
     memset( &cfx, 0, sizeof cfx);
     memset( &afx, 0, sizeof afx);
     memset( &zfx, 0, sizeof zfx);
+    memset( &tfx, 0, sizeof tfx);
     init_packet(&pkt);
 
     if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
@@ -227,6 +234,9 @@ encode_crypt( const char *filename, STRLIST remusr )
     else if( opt.verbose )
        log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
 
+    if( opt.textmode )
+       iobuf_push_filter( inp, text_filter, &tfx );
+
     if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
        goto leave;
 
@@ -270,14 +280,14 @@ encode_crypt( const char *filename, STRLIST remusr )
        pt = m_alloc( sizeof *pt - 1 );
        pt->namelen = 0;
     }
-    if( filename ) {
+    if( filename && !opt.textmode ) {
        if( !(filesize = iobuf_get_filelength(inp)) )
            log_info(_("%s: WARNING: empty file\n"), filename );
     }
     else
        filesize = 0; /* stdin */
     pt->timestamp = make_timestamp();
-    pt->mode = 'b';
+    pt->mode = opt.textmode ? 't' : 'b';
     pt->len = filesize;
     pt->new_ctb = !pt->len && !opt.rfc1991;
     pt->buf = inp;
index 06d660e..c78cb34 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -824,6 +824,7 @@ main( int argc, char **argv )
     secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */
 
     set_debug();
+    g10_opt_homedir = opt.homedir;
 
     /* must do this after dropping setuid, because string_to...
      * may try to load an module */
index 424590e..4d16ecd 100644 (file)
@@ -31,6 +31,7 @@
 #include "keydb.h"
 #include "options.h"
 #include "main.h"
+#include "trustdb.h"
 #include "i18n.h"
 
 #define MAX_UNK_CACHE_ENTRIES 1000   /* we use a linked list - so I guess
@@ -832,6 +833,34 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
 
 
 
+/****************
+ * Search for a key with the given lid and return the complete keyblock
+ */
+int
+get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
+{
+    int rc;
+    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+    struct getkey_ctx_s ctx;
+    u32 kid[2];
+
+    if( keyid_from_lid( lid, kid ) )
+       kid[0] = kid[1] = 0;
+    memset( &ctx, 0, sizeof ctx );
+    ctx.not_allocated = 1;
+    ctx.nitems = 1;
+    ctx.items[0].mode = 12;
+    ctx.items[0].keyid[0] = kid[0];
+    ctx.items[0].keyid[1] = kid[1];
+    rc = lookup_pk( &ctx, pk, ret_keyblock );
+    get_pubkey_end( &ctx );
+
+    free_public_key( pk );
+    return rc;
+}
+
+
+
 
 
 /****************
index 43862d2..88bdccf 100644 (file)
@@ -144,6 +144,7 @@ int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint,
                                                 size_t fprint_len );
 int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
                                                 size_t fprint_len );
+int get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid );
 int seckey_available( u32 *keyid );
 int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
 int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,
index c41e723..dd91fcc 100644 (file)
@@ -182,6 +182,14 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
      * function to check it. */
     if( opt.verbose )
        log_info(_("public key is %08lX\n"), (ulong)enc->keyid[1] );
+
+    if( is_status_enabled() ) {
+       char buf[50];
+       sprintf(buf, "%08lX%08lX", (ulong)enc->keyid[0], (ulong)enc->keyid[1]);
+       write_status_text( STATUS_ENC_TO, buf );
+    }
+
+
     if( is_ELGAMAL(enc->pubkey_algo)
        || enc->pubkey_algo == PUBKEY_ALGO_DSA
        || is_RSA(enc->pubkey_algo)  ) {
@@ -914,7 +922,11 @@ check_sig_and_print( CTX c, KBNODE node )
            g10_exit(1);
     }
     else {
-       write_status( STATUS_ERRSIG );
+       char buf[50];
+       sprintf(buf, "%08lX%08lX %d",
+                    (ulong)sig->keyid[0], (ulong)sig->keyid[1],
+                    sig->pubkey_algo );
+       write_status_text( STATUS_ERRSIG, buf );
        log_error(_("Can't check signature: %s\n"), g10_errstr(rc) );
     }
     return rc;
index 785d21d..6da5280 100644 (file)
@@ -133,6 +133,16 @@ passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode )
                                            :DEFAULT_DIGEST_ALGO;
     }
 
+    if( keyid && !next_pw && is_status_enabled() ) {
+       char buf[50];
+       sprintf( buf, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1] );
+       if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
+                                && keyid[1] != keyid[3] )
+           sprintf( buf+strlen(buf), " %08lX%08lX",
+                                     (ulong)keyid[2], (ulong)keyid[3] );
+       write_status_text( STATUS_NEED_PASSPHRASE, buf );
+    }
+
     if( keyid && !opt.batch && !next_pw ) {
        PKT_public_key *pk = m_alloc_clear( sizeof *pk );
        size_t n;
@@ -159,15 +169,6 @@ passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode )
        tty_printf("\n");
        free_public_key( pk );
     }
-    else if( keyid && !next_pw ) {
-       char buf[50];
-       sprintf( buf, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1] );
-       if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
-                                && keyid[1] != keyid[3] )
-           sprintf( buf+strlen(buf), " %08lX%08lX",
-                                     (ulong)keyid[2], (ulong)keyid[3] );
-       write_status_text( STATUS_NEED_PASSPHRASE, buf );
-    }
 
     if( next_pw ) {
        pw = next_pw;
index fffaef8..57c36ce 100644 (file)
@@ -107,8 +107,8 @@ show_paths( ulong lid, int only_first )
 /****************
  * Returns true if an ownertrust has changed.
  */
-int
-edit_ownertrust( ulong lid, int mode )
+static int
+do_edit_ownertrust( ulong lid, int mode, unsigned *new_trust )
 {
     char *p;
     int rc;
@@ -117,6 +117,7 @@ edit_ownertrust( ulong lid, int mode )
     PKT_public_key *pk ;
     int changed=0;
     int quit=0;
+    int show=0;
 
     rc = keyid_from_lid( lid, keyid );
     if( rc ) {
@@ -177,14 +178,15 @@ edit_ownertrust( ulong lid, int mode )
              case '4': trust = TRUST_FULLY    ; break;
              default: BUG();
            }
-           if( !update_ownertrust( lid, trust ) )
-               changed++;
+           *new_trust = trust;
+           changed = 1;
            break;
        }
        else if( *p == ans[0] || *p == ans[1] ) {
            tty_printf(_(
                "Certificates leading to an ultimately trusted key:\n"));
-           show_paths( lid, 1  );
+           show = 1;
+           break;
        }
        else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) {
            break ; /* back to the menu */
@@ -197,73 +199,71 @@ edit_ownertrust( ulong lid, int mode )
     }
     m_free(p);
     m_free(pk);
-    return quit? -1 : changed;
+    return show? -2: quit? -1 : changed;
+}
+
+
+int
+edit_ownertrust( ulong lid, int mode )
+{
+    unsigned trust;
+
+    for(;;) {
+       switch( do_edit_ownertrust( lid, mode, &trust ) ) {
+         case -1:
+           return 0;
+         case -2:
+           show_paths( lid, 1  );
+           break;
+         case 1:
+           if( !update_ownertrust( lid, trust ) )
+               return 1;
+           return 0;
+         default:
+           return 0;
+       }
+    }
 }
 
+static int
+add_ownertrust_cb( ulong lid )
+{
+    unsigned trust;
+    int rc = do_edit_ownertrust( lid, 0, &trust );
+
+    if( rc == 1 )
+       return trust & TRUST_MASK;
+    return rc > 0? 0 : rc;
+}
 
 /****************
  * Try to add some more owner trusts (interactive)
  * This function presents all the signator in a certificate
- * chain who have no trust value assigned.
+ * chain who have no ownertrust value assigned.
  * Returns: -1 if no ownertrust were added.
  */
 static int
-add_ownertrust( PKT_public_key *pk, int *quit )
+add_ownertrust( PKT_public_key *pk, int *quit, unsigned *trustlevel )
 {
     int rc;
-    void *context = NULL;
-    ulong lid;
-    unsigned otrust, validity;
-    int any=0, changed=0, any_undefined=0;
+    unsigned flags = 0;
 
     *quit = 0;
+    *trustlevel = 0;
     tty_printf(
 _("Could not find a valid trust path to the key.  Let's see whether we\n"
   "can assign some missing owner trust values.\n\n"));
 
-    rc = query_trust_record( pk );
-    if( rc ) {
-       log_error("Ooops: not in trustdb\n");
-       return -1;
-    }
-
-    lid = pk->local_id;
-    while( enum_cert_paths( &context, &lid, &otrust, &validity ) != -1 ) {
-       if( lid == pk->local_id )
-           continue;
-       any=1;
-       if( changed ) {
-           /* because enum_cert_paths() makes a snapshop of the
-            * trust paths, the otrust and validity are not anymore
-            * valid after changing an entry - we have to reread
-            * those values from then on
-            */
-           otrust = get_ownertrust( lid );
-           /* fixme: and the validity? */
-       }
-       if( otrust == TRUST_UNDEFINED ) {
-           any_undefined=1;
-           enum_cert_paths_print( &context, NULL, changed, lid );
-           tty_printf("\n");
-           rc = edit_ownertrust( lid, 0 );
-           if( rc == -1 ) {
-               *quit = 1;
-               break;
-           }
-           else if( rc > 0 )
-              changed = 1;
-       }
-    }
-    enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */
+    rc = check_trust( pk, trustlevel, NULL, add_ownertrust_cb, &flags );
 
-    if( !any )
+    if( !(flags & 1) )
        tty_printf(_("No path leading to one of our keys found.\n\n") );
-    else if( !any_undefined )
+    else if( !(flags & 2) )
        tty_printf(_("No certificates with undefined trust found.\n\n") );
-    else if( !changed )
+    else if( !(flags & 4) )
        tty_printf(_("No trust values changed.\n\n") );
 
-    return changed? 0:-1;
+    return (flags & 4)? 0:-1;
 }
 
 /****************
@@ -274,7 +274,9 @@ static int
 do_we_trust( PKT_public_key *pk, int trustlevel )
 {
     int rc;
+    int did_add = 0;
 
+  retry:
     if( (trustlevel & TRUST_FLAG_REVOKED) ) {
        log_info(_("key %08lX: key has been revoked!\n"),
                                        (ulong)keyid_from_pk( pk, NULL) );
@@ -295,7 +297,7 @@ do_we_trust( PKT_public_key *pk, int trustlevel )
                                                      g10_errstr(rc) );
            return 0; /* no */
        }
-       rc = check_trust( pk, &trustlevel, NULL );
+       rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
        if( rc )
            log_fatal("trust check after insert failed: %s\n",
                                                      g10_errstr(rc) );
@@ -317,14 +319,10 @@ do_we_trust( PKT_public_key *pk, int trustlevel )
        else {
            int quit;
 
-           rc = add_ownertrust( pk, &quit );
-           if( !rc && !quit ) {
-               rc = check_trust( pk, &trustlevel, NULL );
-               if( rc )
-                   log_fatal("trust check after add_ownertrust failed: %s\n",
-                                                             g10_errstr(rc) );
-               /* fixme: this is recursive; we should unroll it */
-               return do_we_trust( pk, trustlevel );
+           rc = add_ownertrust( pk, &quit, &trustlevel );
+           if( !rc && !did_add && !quit ) {
+               did_add = 1;
+               goto retry;
            }
        }
        return 0;
@@ -353,10 +351,6 @@ do_we_trust( PKT_public_key *pk, int trustlevel )
       default: BUG();
     }
 
-
-    /* Eventuell fragen falls der trustlevel nicht ausreichend ist */
-
-
     return 1; /* yes */
 }
 
@@ -419,7 +413,7 @@ check_signatures_trust( PKT_signature *sig )
 {
     PKT_public_key *pk = m_alloc_clear( sizeof *pk );
     int trustlevel;
-    int dont_try = 0;
+    int did_add = 0;
     int rc=0;
 
     rc = get_pubkey( pk, sig->keyid );
@@ -429,13 +423,13 @@ check_signatures_trust( PKT_signature *sig )
        goto leave;
     }
 
-  retry:
-    rc = check_trust( pk, &trustlevel, NULL );
+    rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
     if( rc ) {
        log_error("check trust failed: %s\n", g10_errstr(rc));
        goto leave;
     }
 
+  retry:
     if( (trustlevel & TRUST_FLAG_REVOKED) ) {
        write_status( STATUS_KEYREVOKED );
        log_info(_("WARNING: This key has been revoked by its owner!\n"));
@@ -451,7 +445,7 @@ check_signatures_trust( PKT_signature *sig )
                                                      g10_errstr(rc) );
            goto leave;
        }
-       rc = check_trust( pk, &trustlevel, NULL );
+       rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
        if( rc )
            log_fatal("trust check after insert failed: %s\n",
                                                      g10_errstr(rc) );
@@ -464,7 +458,7 @@ check_signatures_trust( PKT_signature *sig )
        break;
 
       case TRUST_UNDEFINED:
-       if( dont_try || opt.batch || opt.answer_no ) {
+       if( did_add || opt.batch || opt.answer_no ) {
            write_status( STATUS_TRUST_UNDEFINED );
            log_info(_(
            "WARNING: This key is not certified with a trusted signature!\n"));
@@ -474,9 +468,9 @@ check_signatures_trust( PKT_signature *sig )
        }
        else {
            int quit;
-           rc = add_ownertrust( pk, &quit );
+           rc = add_ownertrust( pk, &quit, &trustlevel );
            if( rc || quit ) {
-               dont_try = 1;
+               did_add = 1;
                rc = 0;
            }
            goto retry;
@@ -591,7 +585,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
            else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
                int trustlevel;
 
-               rc = check_trust( pk, &trustlevel, NULL );
+               rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
                if( rc ) {
                    log_error("error checking pk of `%s': %s\n",
                                                      answer, g10_errstr(rc) );
@@ -630,7 +624,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
            else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
                int trustlevel;
 
-               rc = check_trust( pk, &trustlevel, NULL );
+               rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
                if( rc ) {
                    free_public_key( pk ); pk = NULL;
                    log_error(_("%s: error checking key: %s\n"),
index 661f1da..7f0d41e 100644 (file)
@@ -32,6 +32,7 @@
 #include "main.h"
 #include "options.h"
 #include "i18n.h"
+#include "status.h"
 
 
 static int
@@ -175,6 +176,14 @@ check_secret_key( PKT_secret_key *sk, int n )
        if( i )
            log_info(_("Invalid passphrase; please try again ...\n"));
        rc = do_check( sk );
+       if( rc == G10ERR_BAD_PASS && is_status_enabled() ) {
+           u32 kid[2];
+           char buf[50];
+
+           keyid_from_sk( sk, kid );
+           sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]);
+           write_status_text( STATUS_BAD_PASSPHRASE, buf );
+       }
        if( have_static_passphrase() )
            break;
     }
index e34dda3..1b6dc10 100644 (file)
@@ -99,6 +99,11 @@ write_status_text ( int no, const char *text)
       case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE\n"; break;
       case STATUS_VALIDSIG      : s = "VALIDSIG\n"; break;
       case STATUS_SIG_ID        : s = "SIG_ID\n"; break;
+      case STATUS_ENC_TO        : s = "ENC_TO\n"; break;
+      case STATUS_NODATA        : s = "NODATA\n"; break;
+      case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE\n"; break;
+      case STATUS_NO_PUBKEY     : s = "NO_PUBKEY\n"; break;
+      case STATUS_NO_SECKEY     : s = "NO_SECKEY\n"; break;
       default: s = "?\n"; break;
     }
 
index 734c299..7beb321 100644 (file)
 #define STATUS_NEED_PASSPHRASE 20
 #define STATUS_VALIDSIG        21
 #define STATUS_SIG_ID         22
+#define STATUS_ENC_TO         23
+#define STATUS_NODATA         24
+#define STATUS_BAD_PASSPHRASE  25
+#define STATUS_NO_PUBKEY       26
+#define STATUS_NO_SECKEY       27
 
 /*-- status.c --*/
 void set_status_fd ( int fd );
index 22592ae..9bcb6aa 100644 (file)
@@ -633,12 +633,15 @@ tdbio_read_modify_stamp( int modify_down )
 }
 
 void
-tdbio_write_modify_stamp( int down, int up )
+tdbio_write_modify_stamp( int up, int down )
 {
     TRUSTREC vr;
     int rc;
     ulong stamp;
 
+    if( !(up || down) )
+       return;
+
     rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
     if( rc )
        log_fatal( _("%s: error reading version record: %s\n"),
@@ -651,7 +654,7 @@ tdbio_write_modify_stamp( int down, int up )
        vr.r.ver.mod_up = stamp;
 
     rc = tdbio_write_record( &vr );
-    if( !rc )
+    if( rc )
        log_fatal( _("%s: error writing version record: %s\n"),
                                       db_name, g10_errstr(rc) );
 }
index 9c97dd1..ca9d23e 100644 (file)
@@ -176,7 +176,7 @@ 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 );
+void tdbio_write_modify_stamp( int up, int down );
 int tdbio_is_dirty(void);
 int tdbio_sync(void);
 int tdbio_begin_transaction(void);
index 557b4cc..88e06c3 100644 (file)
@@ -41,6 +41,7 @@
 #include "main.h"
 #include "i18n.h"
 #include "tdbio.h"
+#include "ttyio.h"
 
 #if MAX_FINGERPRINT_LEN > 20
   #error Must change structure of trustdb
@@ -115,16 +116,20 @@ static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
 static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
 
 
-static void propagate_validity( TN node );
+static int propagate_validity( TN root, TN node,
+                              int (*add_fnc)(ulong), unsigned *retflgs );
 
-static void print_user_id( const char *text, u32 *keyid );
-static int do_check( TRUSTREC *drec, unsigned *trustlevel, const char *nhash);
+static void print_user_id( FILE *fp, const char *text, u32 *keyid );
+static int do_check( TRUSTREC *drec, unsigned *trustlevel,
+                    const char *nhash, int (*add_fnc)(ulong),
+                                               unsigned *retflgs);
 static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
 
 static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig );
 static void upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                 TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
-                TRUSTREC *urec, const byte *uidhash, int revoked );
+                TRUSTREC *urec, const byte *uidhash, int revoked,
+                                       int *mod_up, int *mod_down );
 
 /* a table used to keep track of ultimately trusted keys
  * which are the ones from our secrings and the trusted keys */
@@ -375,6 +380,7 @@ keyid_from_lid( ulong lid, u32 *keyid )
     int rc;
 
     init_trustdb();
+    keyid[0] = keyid[1] = 0;
     rc = tdbio_read_record( lid, &rec, 0 );
     if( rc ) {
        log_error(_("error reading dir record for LID %lu: %s\n"),
@@ -622,20 +628,23 @@ init_trustdb()
  ************* Print helpers   ****************
  ***********************************************/
 static void
-print_user_id( const char *text, u32 *keyid )
+print_user_id( FILE *fp, const char *text, u32 *keyid )
 {
     char *p;
     size_t n;
 
     p = get_user_id( keyid, &n );
-    if( *text ) {
-       fputs( text, stdout);
-       putchar(' ');
-    }
-    putchar('\"');
-    print_string( stdout, p, n, 0 );
-    putchar('\"');
-    putchar('\n');
+    if( fp ) {
+       fprintf( fp, "%s \"", text );
+       print_string( fp, p, n, 0 );
+       putc('\"', fp);
+       putc('\n', fp);
+    }
+    else {
+       tty_printf( "%s \"", text );
+       tty_print_string( p, n );
+       tty_printf( "\"\n" );
+    }
     m_free(p);
 }
 
@@ -699,35 +708,122 @@ print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
 
 
 static void
-print_default_uid( ulong lid )
+print_default_uid( FILE *fp, ulong lid )
 {
     u32 keyid[2];
 
     if( !keyid_from_lid( lid, keyid ) )
-       print_user_id( "", keyid );
+       print_user_id( fp, "", keyid );
 }
 
 
 static void
-dump_tn_tree( int indent, TN tree )
+print_uid_from_keyblock( FILE *fp, KBNODE keyblock, ulong urecno )
+{
+    TRUSTREC urec;
+    KBNODE node;
+    byte uhash[20];
+
+    read_record( urecno, &urec, RECTYPE_UID );
+    for( node=keyblock; node; node = node->next ) {
+       if( node->pkt->pkttype == PKT_USER_ID ) {
+           PKT_user_id *uidpkt = node->pkt->pkt.user_id;
+
+           rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
+           if( !memcmp( uhash, urec.r.uid.namehash, 20 ) ) {
+               print_string( fp,  uidpkt->name, uidpkt->len, ':' );
+               return;
+           }
+       }
+    }
+
+    fputs("[?]", fp );
+}
+
+
+
+static void
+dump_tn_tree( FILE *fp, int level, TN tree )
 {
     TN kr, ur;
 
     for( kr=tree; kr; kr = kr->next ) {
-       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 );
+       if( fp ) {
+           fprintf( fp, "%*s", level*4, "" );
+           fprintf( fp, "K%lu(ot=%d,val=%d)  ", kr->lid,
+                                            kr->n.k.ownertrust,
+                                            kr->n.k.validity  );
+       }
+       else {
+           tty_printf("%*s", level*4, "" );
+           tty_printf("K%lu(ot=%d,val=%d)  ", kr->lid,
+                                            kr->n.k.ownertrust,
+                                            kr->n.k.validity  );
+       }
+       print_default_uid( fp, kr->lid );
+       for( ur=kr->list; ur; ur = ur->next ) {
+           if( fp ) {
+               fprintf(fp, "%*s  ", level*4, "" );
+               fprintf(fp, "U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
+                                                    ur->n.u.marginal_count,
+                                                    ur->n.u.fully_count,
+                                                    ur->n.u.validity
+                                               );
+           }
+           else {
+               tty_printf("%*s  ", level*4, "" );
+               tty_printf("U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
+                                                    ur->n.u.marginal_count,
+                                                    ur->n.u.fully_count,
+                                                    ur->n.u.validity
+                                               );
+           }
+           dump_tn_tree( fp, level+1, ur->list );
+       }
+    }
+}
+
+/****************
+ * Special version of dump_tn_tree, which prints it colon delimited.
+ * Format:
+ *   level:keyid:type:recno:ot:val:mc:cc:name:
+ * With TYPE = U for a user ID
+ *            K for a key
+ * The RECNO is either the one of the dir record or the one of the uid record.
+ * OT is the the usual trust letter and only availabel on K lines.
+ * VAL is the calcualted validity
+ * MC is the marginal trust counter and only available on U lines
+ * CC is the same for the complete count
+ * NAME ist the username and only printed on U lines
+ */
+static void
+dump_tn_tree_with_colons( int level, TN tree )
+{
+    TN kr, ur;
+
+    for( kr=tree; kr; kr = kr->next ) {
+       KBNODE kb = NULL;
+       u32 kid[2];
+
+       keyid_from_lid( kr->lid, kid );
+       get_keyblock_bylid( &kb, kr->lid );
+
+       printf( "%d:%08lX%08lX:K:%lu:%c:%c::::\n",
+                       level, (ulong)kid[0], (ulong)kid[1], kr->lid,
+                       trust_letter( kr->n.k.ownertrust ),
+                       trust_letter( kr->n.k.validity ) );
        for( ur=kr->list; ur; ur = ur->next ) {
-           printf("%*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 );
+           printf( "%d:%08lX%08lX:U:%lu::%c:%d:%d:",
+                       level, (ulong)kid[0], (ulong)kid[1], ur->lid,
+                       trust_letter( kr->n.u.validity ),
+                       ur->n.u.marginal_count,
+                       ur->n.u.fully_count );
+           print_uid_from_keyblock( stdout, kb, ur->lid );
+           putchar(':');
+           putchar('\n');
+           dump_tn_tree_with_colons( level+1, ur->list );
        }
+       release_kbnode( kb );
     }
 }
 
@@ -851,6 +947,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
  * Process a hintlist.
  * Fixme: this list is not anymore anchored to another
  *       record, so it should be put elsewehere in case of an error
+ * FIXME: add mod_up/down handling
  */
 static void
 process_hintlist( ulong hintlist, ulong hint_owner )
@@ -1184,7 +1281,8 @@ upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
  */
 static void
 upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
-               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
+               TRUSTREC *drec, RECNO_LIST *recno_list,
+               int recheck, int *mod_up, int *mod_down )
 {
     ulong lid = drec->recnum;
     PKT_user_id *uid = uidnode->pkt->pkt.user_id;
@@ -1327,10 +1425,10 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
            write_record( &urec );
            if(   !( urec.r.uid.uidflags & UIDF_VALID )
                || ( urec.r.uid.uidflags & UIDF_REVOKED ) )
-               ; /*FIXME: mark as modified down */
+               *mod_down=1;
            else
-               ; /*FIXME: mark as modified up (maybe a new uuser id)*/
-
+               *mod_up=1; /*(maybe a new user id)*/
+           /* Hmmm, did we catch changed expiration dates? */
        }
 
     } /* end check self-signatures */
@@ -1362,11 +1460,11 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
 
        if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
            upd_cert_record( keyblock, node, keyid, drec, recno_list,
-                            recheck, &urec, uidhash, 0 );
+                            recheck, &urec, uidhash, 0, mod_up, mod_down );
        }
        else if( sig->sig_class == 0x30 ) { /* cert revocation */
            upd_cert_record( keyblock, node, keyid, drec, recno_list,
-                            recheck, &urec, uidhash, 1 );
+                            recheck, &urec, uidhash, 1, mod_up, mod_down );
        }
     } /* end check certificates */
 
@@ -1490,11 +1588,11 @@ upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
 }
 
 
-/* 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 )
+                TRUSTREC *urec, const byte *uidhash, int revoked,
+                int *mod_up, int *mod_down )
 {
     /* We simply insert the signature into the sig records but
      * avoid duplicate ones.  We do not check them here because
@@ -1577,8 +1675,12 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                                revoked? _("Valid certificate revocation")
                                       : _("Good certificate") );
                    rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
-                   if( revoked ) /* we are investigating revocations */
+                   if( revoked ) /* we are investigating revocations */
                        rec.r.sig.sig[i].flag |= SIGF_REVOKED;
+                       *mod_down = 1;
+                   }
+                   else
+                       *mod_up = 1;
                }
                else if( rc == G10ERR_NO_PUBKEY ) {
                    /* This may happen if the key is still in the trustdb
@@ -1589,6 +1691,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                                 uidhash[19], (ulong)sig->keyid[1],
                                 _("public key not anymore available") );
                    rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
+                   *mod_down = 1;
                    if( revoked )
                        rec.r.sig.sig[i].flag |= SIGF_REVOKED;
                }
@@ -1600,8 +1703,10 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                                       : _("Invalid certificate"),
                                                    g10_errstr(rc));
                    rec.r.sig.sig[i].flag = SIGF_CHECKED;
-                   if( revoked )
+                   if( revoked ) {
                        rec.r.sig.sig[i].flag |= SIGF_REVOKED;
+                       *mod_down = 1;
+                   }
                }
                rec.dirty = 1;
            }
@@ -1662,8 +1767,12 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                                       : _("Good certificate") );
        newlid = pk_lid;  /* this is the pk of the signature */
        newflag = SIGF_CHECKED | SIGF_VALID;
-       if( revoked )
+       if( revoked ) {
            newflag |= SIGF_REVOKED;
+           *mod_down = 1;
+       }
+       else
+           *mod_up = 1;
     }
     else if( rc == G10ERR_NO_PUBKEY ) {
        if( opt.verbose > 1 || DBG_TRUST )
@@ -1686,6 +1795,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
        newflag = SIGF_CHECKED;
        if( revoked )
            newflag |= SIGF_REVOKED;
+       *mod_down = 1;
     }
 
     if( delrec.recnum ) { /* we can reuse an unused slot */
@@ -1730,6 +1840,8 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
     int rc = 0;
     u32 keyid[2]; /* keyid of primary key */
     ulong recno, lastrecno;
+    int mod_up = 0;
+    int mod_down = 0;
     RECNO_LIST recno_list = NULL; /* list of verified records */
     /* fixme: replace recno_list by a lookup on node->recno */
 
@@ -1767,7 +1879,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
     for( node=keyblock; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_USER_ID )
            upd_uid_record( keyblock, node, keyid,
-                           &drec, &recno_list, recheck );
+                           &drec, &recno_list, recheck, &mod_up, &mod_down );
     }
 
     /* delete keyrecords from the trustdb which are not anymore used */
@@ -1842,6 +1954,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
        drec.r.dir.dirflags |= DIRF_CHECKED;
        drec.r.dir.valcheck = 0;
        write_record( &drec );
+       tdbio_write_modify_stamp( mod_up, mod_down );
        rc = tdbio_end_transaction();
     }
     rel_recno_list( &recno_list );
@@ -1854,7 +1967,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
  * This function assumes that the record does not yet exist.
  */
 int
-insert_trust_record( PKT_public_key *pk )
+insert_trust_record( PKT_public_key *orig_pk )
 {
     TRUSTREC dirrec;
     TRUSTREC shadow;
@@ -1864,6 +1977,7 @@ insert_trust_record( PKT_public_key *pk )
     size_t fingerlen;
     int rc = 0;
     ulong hintlist = 0;
+    PKT_public_key *pk;
 
 
     if( opt.dry_run )
@@ -1871,7 +1985,7 @@ insert_trust_record( PKT_public_key *pk )
 
     init_trustdb();
 
-    fingerprint_from_pk( pk, fingerprint, &fingerlen );
+    fingerprint_from_pk( orig_pk, fingerprint, &fingerlen );
 
     /* fixme: assert that we do not have this record.
      * we can do this by searching for the primary keyid
@@ -1883,6 +1997,10 @@ insert_trust_record( PKT_public_key *pk )
      * to the primary one which has the user ids etc.)
      */
 
+    if( orig_pk->local_id )
+       log_debug("insert_trust_record with pk->local_id=%lu (1)\n",
+                                                  orig_pk->local_id );
+
     /* get the keyblock which has the key */
     rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
     if( rc ) { /* that should never happen */
@@ -1891,32 +2009,18 @@ insert_trust_record( PKT_public_key *pk )
        goto leave;
     }
 
+    /* make sure that we use the primary key */
+    pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key;
+
     if( pk->local_id ) {
-       log_debug("insert_trust_reord with pk->local_id=%lu\n", pk->local_id );
+       orig_pk->local_id = pk->local_id;
+       log_debug("insert_trust_record with pk->local_id=%lu (2)\n",
+                                                       pk->local_id );
        rc = update_trust_record( keyblock, 1, NULL );
        release_kbnode( keyblock );
        return rc;
     }
 
-    /* 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 );
-
-       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.
@@ -1942,6 +2046,7 @@ insert_trust_record( PKT_public_key *pk )
 
     /* out the LID into the keyblock */
     pk->local_id = dirrec.r.dir.lid;
+    orig_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 ) {
@@ -1954,7 +2059,8 @@ insert_trust_record( PKT_public_key *pk )
        }
     }
 
-    /* FIXME: mark tdb as modified upwards */
+    /* mark tdb as modified upwards */
+    tdbio_write_modify_stamp( 1, 0 );
 
     /* and put all the other stuff into the keydb */
     rc = update_trust_record( keyblock, 1, NULL );
@@ -2100,9 +2206,57 @@ build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
 }
 
 
+static void
+upd_one_ownertrust( ulong lid, unsigned new_trust, unsigned *retflgs )
+{
+    TRUSTREC rec;
+
+    read_record( lid, &rec, RECTYPE_DIR );
+    if( DBG_TRUST )
+       log_debug("upd_one_ownertrust of %lu from %u to %u\n",
+                          lid, (unsigned)rec.r.dir.ownertrust, new_trust );
+    if( retflgs ) {
+       if( new_trust > rec.r.dir.ownertrust )
+           *retflgs |= 16; /* modified up */
+       else
+           *retflgs |= 32; /* modified down */
+    }
+    rec.r.dir.ownertrust = new_trust;
+    write_record( &rec );
+}
 
+/****************
+ * Update the ownertrust in the complete tree.
+ */
 static void
-propagate_validity( TN node )
+propagate_ownertrust( TN kr, ulong lid, unsigned trust )
+{
+    TN ur;
+
+    for( ; kr; kr = kr->next ) {
+       if( kr->lid == lid )
+           kr->n.k.ownertrust = trust;
+       for( ur=kr->list; ur; ur = ur->next )
+           propagate_ownertrust( ur->list, lid, trust );
+    }
+}
+
+/****************
+ * Calculate the validity of all keys in the tree and especially
+ * the one of the top key.  If add_fnc is not NULL, it is used to
+ * ask for missing ownertrust values (but only if this will help
+ * us to increase the validity.
+ * add_fnc is expected to take the LID of the key under question
+ * and return a ownertrust value or an error:  positive values
+ * are assumed to be the new ownertrust value; a 0 does mean no change,
+ * a -1 is a request to cancel this validation procedure, a -2 requests
+ * a listing of the sub-tree using the tty functions.
+ *
+ *
+ * Returns: 0 = okay
+ */
+static int
+propagate_validity( TN root, TN node, int (*add_fnc)(ulong), unsigned *retflgs )
 {
     TN kr, ur;
     int max_validity = 0;
@@ -2112,7 +2266,9 @@ propagate_validity( TN node )
        /* this is one of our keys */
        assert( !node->list ); /* it should be a leaf */
        node->n.k.validity = TRUST_ULTIMATE;
-       return;
+       if( retflgs )
+           *retflgs |= 1;  /* found a path to an ultimately trusted key */
+       return 0;
     }
 
     /* loop over all user ids */
@@ -2120,11 +2276,39 @@ propagate_validity( TN node )
        assert( ur->is_uid );
        /* loop over all signators */
        for(kr=ur->list; kr; kr = kr->next ) {
-           propagate_validity( kr );
+           if( propagate_validity( root, kr, add_fnc, retflgs ) )
+               return -1; /* quit */
            if( kr->n.k.validity == TRUST_ULTIMATE ) {
                ur->n.u.fully_count = opt.completes_needed;
            }
            else if( kr->n.k.validity == TRUST_FULLY ) {
+               if( add_fnc && !kr->n.k.ownertrust ) {
+                   int rc;
+
+                   if( retflgs )
+                       *retflgs |= 2; /* found key with undefined ownertrust*/
+                   do {
+                       rc = add_fnc( kr->lid );
+                       switch( rc ) {
+                         case TRUST_NEVER:
+                         case TRUST_MARGINAL:
+                         case TRUST_FULLY:
+                           propagate_ownertrust( root, kr->lid, rc );
+                           upd_one_ownertrust( kr->lid, rc, retflgs );
+                           if( retflgs )
+                               *retflgs |= 4; /* changed */
+                           break;
+                         case -1:
+                           return -1; /* cancel */
+                         case -2:
+                           dump_tn_tree( NULL, 0, kr );
+                           tty_printf("\n");
+                           break;
+                         default:
+                           break;
+                       }
+                   } while( rc == -2 );
+               }
                if( kr->n.k.ownertrust == TRUST_FULLY )
                    ur->n.u.fully_count++;
                else if( kr->n.k.ownertrust == TRUST_MARGINAL )
@@ -2145,6 +2329,7 @@ propagate_validity( TN node )
     }
 
     node->n.k.validity = max_validity;
+    return 0;
 }
 
 
@@ -2155,15 +2340,17 @@ propagate_validity( TN node )
  * checking all key signatures up to a some depth.
  */
 static int
-verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
+verify_key( int max_depth, TRUSTREC *drec, const char *namehash,
+                           int (*add_fnc)(ulong), unsigned *retflgs )
 {
     TN tree;
     int keytrust;
+    int pv_result;
 
     tree = build_cert_tree( drec->r.dir.lid, 0, opt.max_cert_depth, NULL );
     if( !tree )
        return TRUST_UNDEFINED;
-    propagate_validity( tree );
+    pv_result = propagate_validity( tree, tree, add_fnc, retflgs );
     if( namehash ) {
        /* find the matching user id.
         * fixme: the way we handle this is too inefficient */
@@ -2183,7 +2370,8 @@ verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
        keytrust = tree->n.k.validity;
 
     /* update the cached validity values */
-    if( keytrust >= TRUST_UNDEFINED
+    if( !pv_result
+       && keytrust >= TRUST_UNDEFINED
        && tdbio_db_matches_options()
        && ( !drec->r.dir.valcheck || drec->r.dir.validity != keytrust ) ) {
        TN ur;
@@ -2213,7 +2401,8 @@ verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
  * but nothing more is known.
  */
 static int
-do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
+do_check( TRUSTREC *dr, unsigned *validity,
+         const char *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
 {
     if( !dr->r.dir.keylist ) {
        log_error(_("Ooops, no keys\n"));
@@ -2224,22 +2413,39 @@ do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
        return G10ERR_TRUSTDB;
     }
 
+    if( retflgs )
+       *retflgs &= ~(16|32);  /* reset the 2 special flags */
+
 
     if( namehash ) {
        /* Fixme: use the cache */
-       *validity = verify_key( opt.max_cert_depth, dr, namehash );
+       *validity = verify_key( opt.max_cert_depth, dr, namehash,
+                                                       add_fnc, retflgs );
     }
-    else if( tdbio_db_matches_options()
+    else if( !add_fnc
+       && 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 );
+       *validity = verify_key( opt.max_cert_depth, dr, NULL,
+                                                       add_fnc, retflgs );
+
+    if( !(*validity & TRUST_MASK) )
+       *validity = TRUST_UNDEFINED;
 
     if( dr->r.dir.dirflags & DIRF_REVOKED )
        *validity |= TRUST_FLAG_REVOKED;
 
+    /* If we have changed some ownertrusts, set the trustdb timestamps
+     * and do a sync */
+    if( retflgs && (*retflgs & (16|32)) ) {
+       tdbio_write_modify_stamp( (*retflgs & 16), (*retflgs & 32) );
+       do_sync();
+    }
+
+
     return 0;
 }
 
@@ -2256,6 +2462,9 @@ update_ownertrust( ulong lid, unsigned new_trust )
 
     init_trustdb();
     read_record( lid, &rec, RECTYPE_DIR );
+    if( DBG_TRUST )
+       log_debug("update_ownertrust of %lu from %u to %u\n",
+                          lid, (unsigned)rec.r.dir.ownertrust, new_trust );
     rec.r.dir.ownertrust = new_trust;
     write_record( &rec );
     do_sync();
@@ -2512,7 +2721,8 @@ query_trust_record( PKT_public_key *pk )
  *          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 )
+check_trust( PKT_public_key *pk, unsigned *r_trustlevel,
+            const byte *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
 {
     TRUSTREC rec;
     unsigned trustlevel = TRUST_UNKNOWN;
@@ -2562,7 +2772,7 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte *namehash )
         trustlevel = TRUST_EXPIRED;
     }
     else {
-       rc = do_check( &rec, &trustlevel, namehash );
+       rc = do_check( &rec, &trustlevel, namehash, add_fnc, retflgs );
        if( rc ) {
            log_error(_("key %08lX.%lu: trust check failed: %s\n"),
                            (ulong)keyid[1], pk->local_id, g10_errstr(rc));
@@ -2586,7 +2796,7 @@ query_trust_info( PKT_public_key *pk, const byte *namehash )
     int c;
 
     init_trustdb();
-    if( check_trust( pk, &trustlevel, namehash ) )
+    if( check_trust( pk, &trustlevel, namehash, NULL, NULL ) )
        return '?';
     if( trustlevel & TRUST_FLAG_REVOKED )
        return 'r';
@@ -2656,12 +2866,15 @@ list_trust_path( const char *username )
 
     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 );
+       propagate_validity( tree, tree, NULL, NULL );
+    if( opt.with_colons )
+       dump_tn_tree_with_colons( 0, tree );
+    else
+       dump_tn_tree( stdout, 0, tree );
+    /*printf("(alloced tns=%d  max=%d)\n", alloced_tns, max_alloced_tns );*/
     release_tn_tree( tree );
-    printf("Ownertrust=%c Validity=%c\n", get_ownertrust_info( lid ),
-                                         query_trust_info( pk, NULL ) );
+    /*printf("Ownertrust=%c Validity=%c\n", get_ownertrust_info( lid ),
+                                         query_trust_info( pk, NULL ) ); */
 
     free_public_key( pk );
 
index dba9e5c..64ccaae 100644 (file)
@@ -47,7 +47,8 @@ void check_trustdb( const char *username );
 void update_trustdb( void );
 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 check_trust( PKT_public_key *pk, unsigned *r_trustlevel,
+                const byte* nh, int (*add_fnc)(ulong), unsigned *retflgs );
 int query_trust_info( PKT_public_key *pk, const byte *nh );
 int enum_cert_paths( void **context, ulong *lid,
                     unsigned *ownertrust, unsigned *validity );
index 8e7012f..3c4edc7 100644 (file)
@@ -88,6 +88,7 @@ typedef struct {
 
 int g10c_debug_mode;
 int g10_opt_verbose;
+const char *g10_opt_homedir;
 
 /*-- dynload.c --*/
 void register_cipher_extension( const char *mainpgm, const char *fname );