summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1999-03-11 16:42:06 +0100
committerWerner Koch <wk@gnupg.org>1999-03-11 16:42:06 +0100
commite95a22a6d214edbb604ffe3292ad11ee096bf9a0 (patch)
treedb513c500ee4997d2645cbe71dbda7701e9f213a
parentSee ChangeLog: Wed Mar 10 11:26:18 CET 1999 Werner Koch (diff)
downloadgnupg2-e95a22a6d214edbb604ffe3292ad11ee096bf9a0.tar.xz
gnupg2-e95a22a6d214edbb604ffe3292ad11ee096bf9a0.zip
See ChangeLog: Thu Mar 11 16:39:46 CET 1999 Werner Koch
-rw-r--r--AUTHORS8
-rw-r--r--ChangeLog4
-rw-r--r--NEWS7
-rw-r--r--TODO9
-rw-r--r--cipher/primegen.c5
-rw-r--r--cipher/rndunix.c45
-rw-r--r--configure.in2
-rw-r--r--doc/DETAILS31
-rw-r--r--doc/gpg.1pod44
-rw-r--r--g10/ChangeLog28
-rw-r--r--g10/Makefile.am1
-rw-r--r--g10/build-packet.c2
-rw-r--r--g10/g10.c13
-rw-r--r--g10/import.c13
-rw-r--r--g10/keyedit.c45
-rw-r--r--g10/options.skel6
-rw-r--r--g10/tdbdump.c522
-rw-r--r--g10/tdbio.c84
-rw-r--r--g10/tdbio.h12
-rw-r--r--g10/trustdb.c2609
-rw-r--r--g10/trustdb.h12
-rw-r--r--scripts/distfiles2
22 files changed, 1896 insertions, 1608 deletions
diff --git a/AUTHORS b/AUTHORS
index 01a837c11..9e6cf1174 100644
--- 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.
diff --git a/ChangeLog b/ChangeLog
index c71ee2ac1..0f61ab113 100644
--- 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 07f84df20..15d5d9e8d 100644
--- 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 2956e8a9e..461abb447 100644
--- 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
diff --git a/cipher/primegen.c b/cipher/primegen.c
index e94842189..c7b5b757d 100644
--- a/cipher/primegen.c
+++ b/cipher/primegen.c
@@ -16,6 +16,11 @@
* 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>
diff --git a/cipher/rndunix.c b/cipher/rndunix.c
index 145f17fbd..46f80eab2 100644
--- a/cipher/rndunix.c
+++ b/cipher/rndunix.c
@@ -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>
diff --git a/configure.in b/configure.in
index f5e9dfc43..1e71eb7bc 100644
--- a/configure.in
+++ b/configure.in
@@ -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
diff --git a/doc/DETAILS b/doc/DETAILS
index e204b44b0..81b9dce5d 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -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
-
-
-
diff --git a/doc/gpg.1pod b/doc/gpg.1pod
index 5fa703dab..e0703e66e 100644
--- a/doc/gpg.1pod
+++ b/doc/gpg.1pod
@@ -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
diff --git a/g10/ChangeLog b/g10/ChangeLog
index f76baf987..a4841c473 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -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
diff --git a/g10/Makefile.am b/g10/Makefile.am
index c062d770e..cf0286d2c 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -33,6 +33,7 @@ common_source = \
keyid.c \
trustdb.c \
trustdb.h \
+ tdbdump.c \
tdbio.c \
tdbio.h \
hkp.h \
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 85c73b0e0..810bd0dc2 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -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
diff --git a/g10/g10.c b/g10/g10.c
index c86961d91..06d660e7b 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -35,10 +35,10 @@
#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));
diff --git a/g10/import.c b/g10/import.c
index 640c234a5..920aafbea 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -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 "
diff --git a/g10/keyedit.c b/g10/keyedit.c
index f818b35df..ad53c37bb 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -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:
diff --git a/g10/options.skel b/g10/options.skel
index 3e6777bb7..e95170b1d 100644
--- a/g10/options.skel
+++ b/g10/options.skel
@@ -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
index 000000000..f2b4ca9f8
--- /dev/null
+++ b/g10/tdbdump.c
@@ -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();
+}
+
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 3ba238c2f..22592ae93 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -82,7 +82,6 @@ static int is_locked;
static int db_fd = -1;
static int in_transaction;
-
static void open_db(void);
@@ -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);
+}
+
+
diff --git a/g10/tdbio.h b/g10/tdbio.h
index 62148d361..9c97dd108 100644
--- a/g10/tdbio.h
+++ b/g10/tdbio.h
@@ -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*/
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 2a37641aa..557b4cc51 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -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))
-
/**********************************************
*********** 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)
/**********************************************
- ************* 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 );
+ }
+}
+
+
+
+
+/**********************************************
+ ****** 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 )
}
-
+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;
}
-
/***********************************************
- ************* 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,450 +563,13 @@ verify_own_keys(void)
}
-static void
-print_user_id( 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');
- m_free(p);
-}
-
-
-static int
-print_sigflags( FILE *fp, unsigned flags )
-{
- if( flags & SIGF_CHECKED ) {
- fprintf(fp,"%c%c%c",
- (flags & SIGF_VALID) ? 'V':'-',
- (flags & SIGF_EXPIRED) ? 'E':'-',
- (flags & SIGF_REVOKED) ? 'R':'-');
- }
- else if( flags & SIGF_NOPUBKEY)
- fputs("?--", fp);
- else
- fputs("---", fp);
- return 3;
-}
-
-/* (a non-recursive algorithm would be easier) */
-static int
-do_list_sigs( ulong root, ulong pk_lid, int depth,
- LOCAL_ID_TABLE lids, unsigned *lineno )
-{
- SIGREC_CONTEXT sx;
- int rc;
- u32 keyid[2];
-
- memset( &sx, 0, sizeof sx );
- sx.lid = pk_lid;
- for(;;) {
- rc = walk_sigrecs( &sx ); /* should we replace it and use */
- if( rc )
- 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;
-}
-
-/****************
- * List all signatures of a public key
- */
-static int
-list_sigs( ulong pubkey_id )
-{
- int rc;
- 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;
-}
-
-/****************
- * 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;
-}
-
-
-
-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 );
- }
-}
-
-
-/****************
- * 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.
- */
-static TN
-build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
-{
- TRUSTREC dirrec;
- TRUSTREC uidrec;
- ulong uidrno;
- TN keynode;
-
- if( depth >= max_depth )
- return NULL;
-
- 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;
-
- /* 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 */
-
- /* 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 );
-
- 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 */
-
- 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
- }
- } /* end loop over sig recs */
- } /* end loop over user ids */
-
- if( !keynode->list ) {
- release_tn_tree( keynode );
- keynode = NULL;
- }
-
- return keynode;
-}
-
-
-
-
-/****************
- * 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 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;
-
- 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;
- }
- }
- }
-
- release_tn_tree( tree );
- return trust;
-}
-
-
-
-
-/****************
- * we have the pubkey record and all needed informations are in the trustdb
- * but nothing more is known.
- */
-static int
-do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
-{
- 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;
- }
-
- if( namehash ) {
- /* Fixme: use the cache */
- *validity = verify_key( opt.max_cert_depth, dr, namehash );
- }
- 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( dr->r.dir.dirflags & DIRF_REVOKED )
- *validity |= TRUST_FLAG_REVOKED;
-
- return 0;
-}
-
-
/****************
* 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 )
+setup_trustdb( int level, const char *dbname )
{
/* just store the args */
if( trustdb_args.init )
@@ -1086,13 +579,16 @@ init_trustdb( int level, const char *dbname )
return 0;
}
-static void
-do_init_trustdb()
+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 )
@@ -1119,196 +615,48 @@ do_init_trustdb()
}
-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 )
+
+/***********************************************
+ ************* Print helpers ****************
+ ***********************************************/
+static void
+print_user_id( const char *text, u32 *keyid )
{
- FILE *fp;
- int is_stdin=0;
- char line[256];
char *p;
- size_t n, fprlen;
- unsigned otrust;
+ size_t n;
- 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;
+ p = get_user_id( keyid, &n );
+ if( *text ) {
+ fputs( text, stdout);
+ putchar(' ');
}
+ putchar('\"');
+ print_string( stdout, p, n, 0 );
+ putchar('\"');
+ putchar('\n');
+ m_free(p);
+}
- 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));
+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 ;
}
- if( ferror(fp) )
- log_error_f(fname, _("read error: %s\n"), strerror(errno) );
- if( !is_stdin )
- fclose(fp);
- do_sync();
}
-
#if 0
static void
print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
@@ -1350,55 +698,6 @@ print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
#endif
-
-static int
-propagate_validity( TN node )
-{
- TN kr, ur;
- int max_validity = 0;
-
- 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( 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;
- }
-
- node->n.k.validity = max_validity;
- return max_validity;
-}
-
-
static void
print_default_uid( ulong lid )
{
@@ -1433,625 +732,10 @@ dump_tn_tree( int indent, TN tree )
}
-void
-list_trust_path( const char *username )
-{
- 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 );
-
- 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 );
-}
-
-
-/****************
- * 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;
-
- for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- if( rec.rectype == RECTYPE_DIR ) {
- TRUSTREC tmp;
- int modified;
-
- if( !rec.r.dir.keylist ) {
- log_info(_("lid %lu: dir record w/o key - skipped\n"),
- recnum);
- count++;
- skip_count++;
- continue;
- }
-
- read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY );
-
- rc = get_keyblock_byfprint( &keyblock,
- tmp.r.key.fingerprint,
- tmp.r.key.fingerprint_len );
- if( rc ) {
- log_error(_("lid %lu: keyblock not found: %s\n"),
- recnum, g10_errstr(rc) );
- count++;
- skip_count++;
- continue;
- }
-
- rc = update_trust_record( keyblock, recheck, &modified );
- if( rc ) {
- log_error(_("lid %lu: update failed: %s\n"),
- recnum, g10_errstr(rc) );
- err_count++;
- }
- else if( modified ) {
- if( opt.verbose )
- log_info(_("lid %lu: updated\n"), recnum );
- upd_count++;
- }
- else if( opt.verbose > 1 )
- log_info(_("lid %lu: okay\n"), recnum );
-
- release_kbnode( keyblock ); keyblock = NULL;
- if( !(++count % 100) )
- log_info(_("%lu keys so far processed\n"), count);
- }
- }
- log_info(_("%lu keys processed\n"), count);
- if( skip_count )
- log_info(_("\t%lu keys skipped\n"), skip_count);
- if( err_count )
- log_info(_("\t%lu keys with errors\n"), err_count);
- if( upd_count )
- log_info(_("\t%lu keys updated\n"), upd_count);
- }
-}
-
-
-/****************
- * Put new entries from the pubrings into the trustdb.
- * This function honors the sig flags to speed up the check.
- */
-void
-update_trustdb( )
-{
- KBNODE keyblock = NULL;
- KBPOS kbpos;
- int rc;
-
- 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;
-
- rc = update_trust_record( keyblock, 1, &modified );
- if( rc == -1 ) { /* not yet in trustdb: insert */
- PKT_public_key *pk =
- find_kbnode( keyblock, PKT_PUBLIC_KEY
- ) ->pkt->pkt.public_key;
- rc = insert_trust_record( pk );
- if( rc && !pk->local_id ) {
- log_error(_("lid ?: insert failed: %s\n"),
- g10_errstr(rc) );
- err_count++;
- }
- else if( rc ) {
- log_error(_("lid %lu: insert failed: %s\n"),
- pk->local_id, g10_errstr(rc) );
- err_count++;
- }
- else {
- if( opt.verbose )
- log_info(_("lid %lu: inserted\n"), pk->local_id );
- new_count++;
- }
- }
- else if( rc ) {
- log_error(_("lid %lu: update failed: %s\n"),
- lid_from_keyblock(keyblock), g10_errstr(rc) );
- err_count++;
- }
- else if( modified ) {
- if( opt.verbose )
- log_info(_("lid %lu: updated\n"), lid_from_keyblock(keyblock));
- upd_count++;
- }
- else if( opt.verbose > 1 )
- log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) );
-
- 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 );
-}
-
-
-/****************
- * 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 );
-
- /* 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 );
- }
- }
- 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;
- }
- }
-
-
- 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;
- }
- return -1;
- }
-
- if( !*context ) {
- FIXME .... *tmppath;
- TRUSTREC rec;
-
- if( !*lid )
- return -1;
-
- 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;
- }
- 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
-}
-
-
-/****************
- * 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;
- }
- }
- }
-
- print_path( tsl->pathlen, tsl->path, fp, selected_lid );
- #endif
-}
-
-
-/****************
- * Return the assigned ownertrust value for the given LID
- */
-unsigned
-get_ownertrust( ulong lid )
-{
- TRUSTREC rec;
-
- INIT_TRUSTDB();
- read_record( lid, &rec, RECTYPE_DIR );
- return rec.r.dir.ownertrust;
-}
-
-int
-get_ownertrust_info( ulong lid )
-{
- unsigned otrust;
- int c;
-
- INIT_TRUSTDB();
- otrust = get_ownertrust( lid );
- c = trust_letter( (otrust & TRUST_MASK) );
- if( !c )
- c = '?';
- return c;
-}
-
-/*
- * Return an allocated buffer with the preference values for
- * the key with LID and the userid which is identified by the
- * HAMEHASH or the firstone if namehash is NULL. ret_n receives
- * the length of the 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;
-
- 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;
-}
-
-
-
-/****************
- * 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;
-
- 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;
- }
- }
- }
- 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));
- }
- 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
- */
-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;
-}
-
-
+/***********************************************
+ ************* trustdb maintenance ***********
+ ***********************************************/
static void
@@ -2272,7 +956,7 @@ create_shadow_dir( PKT_signature *sig, ulong lid )
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();
+ tdbio_invalid();
}
if( rc == -1 ) { /* not found: create */
memset( &sdir, 0, sizeof sdir );
@@ -2367,7 +1051,7 @@ upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
ins_recno_list( recno_list, recno, RECTYPE_KEY );
}
else { /* no: insert this new key */
- recheck = 1;
+ recheck = 1; /* same as recheck */
memset( &krec, 0, sizeof(krec) );
krec.rectype = RECTYPE_KEY;
krec.r.key.lid = lid;
@@ -2408,17 +1092,19 @@ upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
PKT_signature *sig;
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
+ break; /* ready (we check only one key at a time) */
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 */
+ continue; /* here we only care about a self-signatures */
+
if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
- continue; /* oops, not for a main key */
+ continue; /* oops, ignore subkey binding on main key */
+
/* we check until we find a valid keybinding */
rc = check_key_signature( keyblock, node, NULL );
if( !rc ) {
@@ -2440,6 +1126,7 @@ upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
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 ) {
@@ -2523,7 +1210,7 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
ins_recno_list( recno_list, recno, RECTYPE_UID );
}
else { /* new user id */
- recheck = 1;
+ recheck = 1; /* insert is the same as a recheck */
memset( &urec, 0 , sizeof(urec) );
urec.rectype = RECTYPE_UID;
urec.r.uid.lid = drec->recnum;
@@ -2547,8 +1234,10 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
}
if( recheck || !(urec.r.uid.uidflags & UIDF_CHECKED) ) {
- /* check self signatures */
+ unsigned orig_uidflags = urec.r.uid.uidflags;
+
urec.r.uid.uidflags = 0;
+ /* first check regular self signatures */
for( node=uidnode->next; node; node = node->next ) {
PKT_signature *sig;
@@ -2586,7 +1275,29 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
urec.r.uid.uidflags |= UIDF_CHECKED;
}
}
- else if( sig->sig_class == 0x30 ) { /* cert revocation */
+ }
+
+ /* 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;
+
+ 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 == 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",
@@ -2609,8 +1320,19 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
g10_errstr(rc) );
}
}
+
}
- write_record( &urec );
+
+ 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)*/
+
+ }
+
} /* end check self-signatures */
@@ -2622,7 +1344,7 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
if( selfsig )
upd_pref_record( &urec, keyid, selfsig );
- /* check non-self signatures */
+ /* Now we va check the certication signatures */
for( node=uidnode->next; node; node = node->next ) {
PKT_signature *sig;
@@ -2636,7 +1358,7 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
sig = node->pkt->pkt.signature;
if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] )
- continue; /* skip self signature */
+ continue; /* here we skip the self-signatures */
if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
upd_cert_record( keyblock, node, keyid, drec, recno_list,
@@ -2652,11 +1374,6 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
}
-
-/****************
- *
- *
- */
static void
upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
{
@@ -2773,7 +1490,7 @@ 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,
@@ -2785,7 +1502,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
* 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
+ * be converted to a dir record as when the missing public key
* gets inserted into the trustdb.
*/
ulong lid = drec->recnum;
@@ -2796,7 +1513,6 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
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;
@@ -2811,25 +1527,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
delrec.recnum = 0;
/* get the LID of the pubkey of the signature under verification */
- rc = get_pubkey( pk, sig->keyid );
- if( !rc ) {
- if( pk->local_id )
- pk_lid = pk->local_id;
- else {
- rc = tdbio_search_dir_bypk( pk, &rec );
- if( !rc )
- pk_lid = rec.recnum;
- else if( rc == -1 ) { /* see whether there is a sdir instead */
- u32 akid[2];
-
- keyid_from_pk( pk, akid );
- rc = tdbio_search_sdir( akid, pk->pubkey_algo, &rec );
- if( !rc )
- pk_lid = rec.recnum;
- }
- }
- }
- free_public_key( pk ); pk = NULL;
+ 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.
@@ -2841,15 +1539,16 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
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 deleted sigs */
+ continue; /* skip unused slots */
}
+
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],
@@ -2859,17 +1558,16 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
rec.dirty = 1;
continue;
}
- #endif
found_sig = 1;
}
- if( !recheck && !revoked && (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
+ 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 */
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 */
+ /* the public key is in the trustdb: check sig */
rc = check_key_signature( keyblock, signode, NULL );
if( !rc ) { /* valid signature */
if( opt.verbose )
@@ -2879,16 +1577,17 @@ 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 )
+ if( revoked ) /* we are investigating revocations */
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
}
else if( rc == G10ERR_NO_PUBKEY ) {
- /* fixme: For some reason this really happens? */
+ /* 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],
- _("Hmmm, public key lost?") );
+ _("public key not anymore available") );
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
if( revoked )
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
@@ -2929,7 +1628,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
else {
log_error(_("sig record %lu[%d] points to wrong record.\n"),
rec.r.sig.sig[i].lid, i );
- die_invalid_db();
+ tdbio_invalid();
}
}
if( found_delrec && delrec.recnum ) {
@@ -2942,7 +1641,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
}
}
- if( found_sig ) /* fixme: uid stuff */
+ if( found_sig )
return;
/* at this point, we have verified, that the signature is not in
@@ -2989,12 +1688,12 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
newflag |= SIGF_REVOKED;
}
- if( delrec.recnum ) { /* we can reuse a deleted/unused slot */
+ 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 { /* must insert a new sig record */
+ else { /* we must insert a new sig record */
TRUSTREC tmp;
memset( &tmp, 0, sizeof tmp );
@@ -3037,7 +1736,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
if( opt.dry_run )
return 0;
- INIT_TRUSTDB();
+ init_trustdb();
if( modified )
*modified = 0;
@@ -3141,7 +1840,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
if( modified && tdbio_is_dirty() )
*modified = 1;
drec.r.dir.dirflags |= DIRF_CHECKED;
- drec.r.dir.dirflags &= ~DIRF_VALVALID;
+ drec.r.dir.valcheck = 0;
write_record( &drec );
rc = tdbio_end_transaction();
}
@@ -3170,7 +1869,7 @@ insert_trust_record( PKT_public_key *pk )
if( opt.dry_run )
return 0;
- INIT_TRUSTDB();
+ init_trustdb();
fingerprint_from_pk( pk, fingerprint, &fingerlen );
@@ -3179,7 +1878,7 @@ insert_trust_record( PKT_public_key *pk )
*
* 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
+ * 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.)
*/
@@ -3225,7 +1924,7 @@ insert_trust_record( PKT_public_key *pk )
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();
+ tdbio_invalid();
}
memset( &dirrec, 0, sizeof dirrec );
dirrec.rectype = RECTYPE_DIR;
@@ -3241,7 +1940,7 @@ insert_trust_record( PKT_public_key *pk )
dirrec.r.dir.lid = dirrec.recnum;
write_record( &dirrec );
- /* store the LID */
+ /* 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
@@ -3255,6 +1954,8 @@ insert_trust_record( PKT_public_key *pk )
}
}
+ /* FIXME: mark tdb as modified upwards */
+
/* and put all the other stuff into the keydb */
rc = update_trust_record( keyblock, 1, NULL );
if( !rc )
@@ -3269,12 +1970,291 @@ insert_trust_record( PKT_public_key *pk )
}
+
+
+/***********************************************
+ ********* Trust calculation *****************
+ ***********************************************/
+
+/****************
+ * 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 TN
+build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
+{
+ TRUSTREC dirrec;
+ TRUSTREC uidrec;
+ ulong uidrno;
+ TN keynode;
+
+ if( depth >= max_depth )
+ return NULL;
+
+ 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;
+
+ /* 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 */
+
+ /* 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 );
+
+ 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 */
+
+ 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
+ }
+ } /* end loop over sig recs */
+ } /* end loop over user ids */
+
+ if( !keynode->list ) {
+ release_tn_tree( keynode );
+ keynode = NULL;
+ }
+
+ return keynode;
+}
+
+
+
+static void
+propagate_validity( TN node )
+{
+ TN kr, ur;
+ int max_validity = 0;
+
+ 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;
+ }
+
+ /* 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;
+ }
+
+ node->n.k.validity = max_validity;
+}
+
+
+
+/****************
+ * 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;
+ }
+ }
+ }
+ 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 );
+ }
+ }
+
+ drec->r.dir.validity = tree->n.k.validity;
+ drec->r.dir.valcheck = make_timestamp();
+ write_record( drec );
+ do_sync();
+ }
+
+ release_tn_tree( tree );
+ return keytrust;
+}
+
+
+/****************
+ * we have the pubkey record and all needed informations are in the trustdb
+ * but nothing more is known.
+ */
+static int
+do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
+{
+ 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;
+ }
+
+
+ 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 );
+
+ if( dr->r.dir.dirflags & DIRF_REVOKED )
+ *validity |= TRUST_FLAG_REVOKED;
+
+ return 0;
+}
+
+
+
+/***********************************************
+ ********* Change trustdb values **************
+ ***********************************************/
+
int
update_ownertrust( ulong lid, unsigned new_trust )
{
TRUSTREC rec;
- INIT_TRUSTDB();
+ init_trustdb();
read_record( lid, &rec, RECTYPE_DIR );
rec.r.dir.ownertrust = new_trust;
write_record( &rec );
@@ -3283,3 +2263,610 @@ update_ownertrust( ulong lid, unsigned new_trust )
}
+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.valcheck )
+ return 0;
+
+ /* 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.
+ */
+void
+update_trustdb( )
+{
+ KBNODE keyblock = NULL;
+ KBPOS kbpos;
+ 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;
+
+ while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
+ int modified;
+
+ rc = update_trust_record( keyblock, 1, &modified );
+ if( rc == -1 ) { /* not yet in trustdb: insert */
+ PKT_public_key *pk = 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++;
+ }
+ }
+ 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 );
+}
+
+/****************
+ * 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;
+
+ for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
+ if( rec.rectype == RECTYPE_DIR ) {
+ TRUSTREC tmp;
+ int modified;
+
+ if( !rec.r.dir.keylist ) {
+ log_info(_("lid %lu: dir record w/o key - skipped\n"),
+ recnum);
+ count++;
+ skip_count++;
+ continue;
+ }
+
+ read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY );
+
+ rc = get_keyblock_byfprint( &keyblock,
+ tmp.r.key.fingerprint,
+ tmp.r.key.fingerprint_len );
+ if( rc ) {
+ log_error(_("lid %lu: keyblock not found: %s\n"),
+ recnum, g10_errstr(rc) );
+ count++;
+ skip_count++;
+ continue;
+ }
+
+ rc = update_trust_record( keyblock, recheck, &modified );
+ if( rc ) {
+ log_error(_("lid %lu: update failed: %s\n"),
+ recnum, g10_errstr(rc) );
+ err_count++;
+ }
+ else if( modified ) {
+ if( opt.verbose )
+ log_info(_("lid %lu: updated\n"), recnum );
+ upd_count++;
+ }
+ else if( opt.verbose > 1 )
+ log_info(_("lid %lu: okay\n"), recnum );
+
+ release_kbnode( keyblock ); keyblock = NULL;
+ if( !(++count % 100) )
+ log_info(_("%lu keys so far processed\n"), count);
+ }
+ }
+ log_info(_("%lu keys processed\n"), count);
+ if( skip_count )
+ log_info(_("\t%lu keys skipped\n"), skip_count);
+ if( err_count )
+ log_info(_("\t%lu keys with errors\n"), err_count);
+ if( upd_count )
+ log_info(_("\t%lu keys updated\n"), upd_count);
+ }
+}
+
+
+
+/***********************************************
+ ********* Query trustdb values **************
+ ***********************************************/
+
+
+/****************
+ * 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 )
+{
+ TRUSTREC rec;
+ init_trustdb();
+ return get_dir_record( pk, &rec );
+}
+
+
+/****************
+ * 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 );
+
+ /* 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 );
+ }
+ }
+ 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;
+ }
+ }
+
+
+ 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;
+}
+
+
+
+/****************
+ * Return the assigned ownertrust value for the given LID
+ */
+unsigned
+get_ownertrust( ulong lid )
+{
+ TRUSTREC rec;
+
+ init_trustdb();
+ read_record( lid, &rec, RECTYPE_DIR );
+ return rec.r.dir.ownertrust;
+}
+
+int
+get_ownertrust_info( ulong lid )
+{
+ unsigned otrust;
+ int c;
+
+ init_trustdb();
+ otrust = get_ownertrust( lid );
+ c = trust_letter( (otrust & TRUST_MASK) );
+ if( !c )
+ c = '?';
+ return c;
+}
+
+
+
+void
+list_trust_path( const char *username )
+{
+ 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;
+
+ 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 ) );
+
+ 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 );
+ }
+ *context = NULL;
+ }
+ return -1;
+ }
+
+ if( !*context ) {
+ FIXME .... *tmppath;
+ TRUSTREC rec;
+
+ if( !*lid )
+ return -1;
+
+ 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;
+ }
+ 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
+}
+
+
+/****************
+ * 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.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;
+ }
+ }
+ }
+
+ print_path( tsl->pathlen, tsl->path, fp, selected_lid );
+ #endif
+}
+
+
+/*
+ * 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;
+
+ 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;
+}
+
+
+
+/****************
+ * 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;
+
+ 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;
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/g10/trustdb.h b/g10/trustdb.h
index 303ffc761..dba9e5caf 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -41,14 +41,12 @@
/*-- 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 );
diff --git a/scripts/distfiles b/scripts/distfiles
index 804b73f88..13127323a 100644
--- a/scripts/distfiles
+++ b/scripts/distfiles
@@ -7,6 +7,4 @@ missing
gnupg.spec.in
autogen.sh
ChangeLog
-ltconfig
-ltmain.sh