diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/ChangeLog | 49 | ||||
-rw-r--r-- | g10/Makefile.am | 8 | ||||
-rw-r--r-- | g10/encode.c | 6 | ||||
-rw-r--r-- | g10/g10.c | 11 | ||||
-rw-r--r-- | g10/import.c | 135 | ||||
-rw-r--r-- | g10/keyedit.c | 14 | ||||
-rw-r--r-- | g10/main.h | 3 | ||||
-rw-r--r-- | g10/mainproc.c | 18 | ||||
-rw-r--r-- | g10/openfile.c | 54 | ||||
-rw-r--r-- | g10/options.h | 1 | ||||
-rw-r--r-- | g10/options.skel | 37 | ||||
-rw-r--r-- | g10/ringedit.c | 20 | ||||
-rw-r--r-- | g10/sign.c | 5 | ||||
-rw-r--r-- | g10/tdbio.c | 108 | ||||
-rw-r--r-- | g10/tdbio.h | 4 | ||||
-rw-r--r-- | g10/trustdb.c | 1393 | ||||
-rw-r--r-- | g10/trustdb.h | 2 |
17 files changed, 1090 insertions, 778 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index f16a600b6..35afefa16 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,52 @@ +Sun Oct 25 19:32:05 1998 Werner Koch ([email protected]) + + * openfile.c (copy_options_File): New. + * ringedit.c (add_keyblock_resource): Creates options file + * tdbio.c (tdbio_set_dbname): Ditto. + +Sat Oct 24 14:10:53 1998 brian moore <[email protected]> + + * mainproc.c (proc_pubkey_enc): Don't release the DEK + (do_proc_packets): Ditto. + +Fri Oct 23 06:49:38 1998 me,,, (wk@tobold) + + * keyedit.c (keyedit_menu): Comments are now allowed + + * trustdb.c: Rewrote large parts. + + +Thu Oct 22 15:56:45 1998 Michael Roth ([email protected]) + + * encode.c: (encode_simple): Only the plain filename without + a given directory is stored in generated packets. + (encode_crypt): Ditto. + + * sign.c: (sign_file) Ditto. + + +Thu Oct 22 10:53:41 1998 Werner Koch ([email protected]) + + * trustdb.c (update_trust_record): Add new optional arg. + + * import.c (import_keys): Add statistics output + * trustdb.c (update_trustdb): Ditto. + (insert_trustdb): Ditto. + + * tdbio.c (tdbio_begin_transaction): New. + (tdbio_end_transaction): New. + (tdbio_cancel_transaction): New. + + * g10.c (main): New option --quit. + + * trustdb.c (check_hint_sig): No tests for user-id w/o sig. + This caused an assert while checking the sigs. + + * trustdb.c (upd_sig_record): Splitted into several functions. + + * import.c (import_keys): New arg "fast". + * g10.c (main): New command --fast-import. + Wed Oct 21 18:19:36 1998 Michael Roth <[email protected]> * ringedit.c (add_keyblock_resource): Directory is now created. diff --git a/g10/Makefile.am b/g10/Makefile.am index 75838524a..02e3ee525 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -EXTRA_DIST = OPTIONS pubring.asc +EXTRA_DIST = OPTIONS pubring.asc options.skel OMIT_DEPENDENCIES = zlib.h zconf.h LDFLAGS = @LDFLAGS@ @DYNLINK_LDFLAGS@ needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a @@ -87,3 +87,9 @@ g10maint.o: $(srcdir)/g10.c $(PROGRAMS): $(needed_libs) +install-data-local: + $(mkinstalldirs) $(pkgdatadir) + $(INSTALL_DATA) $(srcdir)/options.skel $(pkgdatadir)/options.skel + + + diff --git a/g10/encode.c b/g10/encode.c index 0d8a84c94..371a23731 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -140,10 +140,11 @@ encode_simple( const char *filename, int mode ) /* setup the inner packet */ if( filename || opt.set_filename ) { - const char *s = opt.set_filename ? opt.set_filename : filename; + char *s = make_basename( opt.set_filename ? opt.set_filename : filename ); pt = m_alloc( sizeof *pt + strlen(s) - 1 ); pt->namelen = strlen(s); memcpy(pt->name, s, pt->namelen ); + m_free(s); } else { /* no filename */ pt = m_alloc( sizeof *pt - 1 ); @@ -253,10 +254,11 @@ encode_crypt( const char *filename, STRLIST remusr ) /* setup the inner packet */ if( filename || opt.set_filename ) { - const char *s = opt.set_filename ? opt.set_filename : filename; + char *s = make_basename( opt.set_filename ? opt.set_filename : filename ); pt = m_alloc( sizeof *pt + strlen(s) - 1 ); pt->namelen = strlen(s); memcpy(pt->name, s, pt->namelen ); + m_free(s); } else { /* no filename */ pt = m_alloc( sizeof *pt - 1 ); @@ -57,6 +57,7 @@ enum cmd_and_opt_values { aNull = 0, oKOption = 'k', oDryRun = 'n', oOutput = 'o', + oQuiet = 'q', oRemote = 'r', aSign = 's', oTextmode = 't', @@ -76,6 +77,7 @@ enum cmd_and_opt_values { aNull = 0, aKMode, aKModeC, aImport, + aFastImport, aVerify, aListKeys, aListSigs, @@ -174,6 +176,7 @@ static ARGPARSE_OPTS opts[] = { { aExport, "export" , 256, N_("export keys") }, { aExportSecret, "export-secret-keys" , 256, "@" }, { aImport, "import", 256 , N_("import/merge keys")}, + { aFastImport, "fast-import", 256 , "@"}, { aListPackets, "list-packets",256,N_("list only the sequence of packets")}, #ifdef IS_G10MAINT { aExportOwnerTrust, @@ -206,6 +209,7 @@ static ARGPARSE_OPTS opts[] = { #endif { oOutput, "output", 2, N_("use as output file")}, { oVerbose, "verbose", 0, N_("verbose") }, + { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") }, /* { oDryRun, "dry-run", 0, N_("do not make any changes") }, */ { oBatch, "batch", 0, N_("batch mode: never ask")}, @@ -614,6 +618,7 @@ main( int argc, char **argv ) case aCheckKeys: set_cmd( &cmd, aCheckKeys); break; case aListPackets: set_cmd( &cmd, aListPackets); break; case aImport: set_cmd( &cmd, aImport); break; + case aFastImport: set_cmd( &cmd, aFastImport); break; case aExport: set_cmd( &cmd, aExport); break; case aListKeys: set_cmd( &cmd, aListKeys); break; case aListSigs: set_cmd( &cmd, aListSigs); break; @@ -657,6 +662,7 @@ main( int argc, char **argv ) case oArmor: opt.armor = 1; opt.no_armor=0; break; case oOutput: opt.outfile = pargs.r.ret_str; break; + case oQuiet: opt.quiet = 1; break; case oVerbose: g10_opt_verbose++; opt.verbose++; opt.list_sigs=1; break; case oKOption: set_cmd( &cmd, aKMode ); break; @@ -1022,14 +1028,15 @@ main( int argc, char **argv ) break; #endif + case aFastImport: case aImport: if( !argc ) { - rc = import_keys( NULL ); + rc = import_keys( NULL, (cmd == aFastImport) ); if( rc ) log_error("import failed: %s\n", g10_errstr(rc) ); } for( ; argc; argc--, argv++ ) { - rc = import_keys( *argv ); + rc = import_keys( *argv, (cmd == aFastImport) ); if( rc ) log_error("import from '%s' failed: %s\n", *argv, g10_errstr(rc) ); diff --git a/g10/import.c b/g10/import.c index 374843363..075ecd358 100644 --- a/g10/import.c +++ b/g10/import.c @@ -36,9 +36,24 @@ #include "i18n.h" +static struct { + ulong no_user_id; + ulong imported; + ulong imported_rsa; + ulong n_uids; + ulong n_sigs; + ulong n_subk; + ulong unchanged; + ulong n_revoc; + ulong secret_read; + ulong secret_imported; + ulong secret_dups; +} stats; + + static int read_block( IOBUF a, compress_filter_context_t *cfx, PACKET **pending_pkt, KBNODE *ret_root ); -static int import_one( const char *fname, KBNODE keyblock ); +static int import_one( const char *fname, KBNODE keyblock, int fast ); static int import_secret_one( const char *fname, KBNODE keyblock ); static int import_revoke_cert( const char *fname, KBNODE node ); static int chk_self_sigs( const char *fname, KBNODE keyblock, @@ -59,7 +74,7 @@ static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, * least one userid. Only user ids which are self signed will be imported. * Other signatures are not checked. * - * Actually this functtion does a merge. It works like this: + * Actually this function does a merge. It works like this: * * - get the keyblock * - check self-signatures and remove all userids and their signatures @@ -85,7 +100,7 @@ static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, * */ int -import_keys( const char *fname ) +import_keys( const char *fname, int fast ) { armor_filter_context_t afx; compress_filter_context_t cfx; @@ -93,11 +108,15 @@ import_keys( const char *fname ) IOBUF inp = NULL; KBNODE keyblock; int rc = 0; + ulong count=0; memset( &afx, 0, sizeof afx); memset( &cfx, 0, sizeof cfx); afx.only_keyblocks = 1; + /* fixme: don't use static variables */ + memset( &stats, 0, sizeof( stats ) ); + /* open file */ inp = iobuf_open(fname); if( !fname ) @@ -112,7 +131,7 @@ import_keys( const char *fname ) while( !(rc = read_block( inp, &cfx, &pending_pkt, &keyblock) )) { if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ) - rc = import_one( fname, keyblock ); + rc = import_one( fname, keyblock, fast ); else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) rc = import_secret_one( fname, keyblock ); else if( keyblock->pkt->pkttype == PKT_SIGNATURE @@ -125,12 +144,41 @@ import_keys( const char *fname ) release_kbnode(keyblock); if( rc ) break; + if( !(++count % 100) ) + log_info(_("%lu keys so far processed\n"), count ); } if( rc == -1 ) rc = 0; else if( rc && rc != G10ERR_INV_KEYRING ) log_error_f( fname, _("read error: %s\n"), g10_errstr(rc)); + log_info(_("Total number processed: %lu\n"), count ); + if( stats.no_user_id ) + log_info(_(" w/o user IDs: %lu\n"), stats.no_user_id ); + if( stats.imported || stats.imported_rsa ) { + log_info(_(" imported: %lu"), stats.imported ); + if( stats.imported_rsa ) + fprintf(stderr, " (RSA: %lu)", stats.imported_rsa ); + putc('\n', stderr); + } + if( stats.unchanged ) + log_info(_(" unchanged: %lu\n"), stats.unchanged ); + if( stats.n_uids ) + log_info(_(" new user IDs: %lu\n"), stats.n_uids ); + if( stats.n_subk ) + log_info(_(" new subkeys: %lu\n"), stats.n_subk ); + if( stats.n_sigs ) + log_info(_(" new signatures: %lu\n"), stats.n_sigs ); + if( stats.n_revoc ) + log_info(_(" new key revocations: %lu\n"), stats.n_revoc ); + if( stats.secret_read ) + log_info(_(" secret keys read: %lu\n"), stats.secret_read ); + if( stats.secret_imported ) + log_info(_(" secret keys imported: %lu\n"), stats.secret_imported ); + if( stats.secret_dups ) + log_info(_(" secret keys unchanged: %lu\n"), stats.secret_dups ); + + iobuf_close(inp); return rc; } @@ -238,7 +286,7 @@ read_block( IOBUF a, compress_filter_context_t *cfx, * which called g10. */ static int -import_one( const char *fname, KBNODE keyblock ) +import_one( const char *fname, KBNODE keyblock, int fast ) { PKT_public_key *pk; PKT_public_key *pk_orig; @@ -280,9 +328,12 @@ import_one( const char *fname, KBNODE keyblock ) return rc== -1? 0:rc; if( !delete_inv_parts( fname, keyblock, keyid ) ) { - log_info_f( fname, _("key %08lX: no valid user ids\n"), - (ulong)keyid[1]); - log_info(_("this may be caused by a missing self-signature\n")); + if( !opt.quiet ) { + log_info_f( fname, _("key %08lX: no valid user ids\n"), + (ulong)keyid[1]); + log_info(_("this may be caused by a missing self-signature\n")); + } + stats.no_user_id++; return 0; } @@ -311,7 +362,12 @@ import_one( const char *fname, KBNODE keyblock ) _("can't write to keyring: %s\n"), g10_errstr(rc) ); unlock_keyblock( &kbpos ); /* we are ready */ - log_info_f( fname, _("key %08lX: public key imported\n"), (ulong)keyid[1]); + if( !opt.quiet ) + log_info_f( fname, _("key %08lX: public key imported\n"), + (ulong)keyid[1]); + stats.imported++; + if( is_RSA( pk->pubkey_algo ) ) + stats.imported_rsa++; new_key = 1; } else { /* merge */ @@ -366,29 +422,39 @@ import_one( const char *fname, KBNODE keyblock ) _("can't write keyblock: %s\n"), g10_errstr(rc) ); unlock_keyblock( &kbpos ); /* we are ready */ - if( n_uids == 1 ) - log_info_f(fname, _("key %08lX: 1 new user-id\n"), - (ulong)keyid[1]); - else if( n_uids ) - log_info_f(fname, _("key %08lX: %d new user-ids\n"), - (ulong)keyid[1], n_uids ); - if( n_sigs == 1 ) - log_info_f(fname, _("key %08lX: 1 new signature\n"), - (ulong)keyid[1]); - else if( n_sigs ) - log_info_f(fname, _("key %08lX: %d new signatures\n"), - (ulong)keyid[1], n_sigs ); - if( n_subk == 1 ) - log_info_f(fname, _("key %08lX: 1 new subkey\n"), - (ulong)keyid[1]); - else if( n_subk ) - log_info_f(fname, _("key %08lX: %d new subkeys\n"), - (ulong)keyid[1], n_subk ); + if( !opt.quiet ) { + if( n_uids == 1 ) + log_info_f(fname, _("key %08lX: 1 new user-id\n"), + (ulong)keyid[1]); + else if( n_uids ) + log_info_f(fname, _("key %08lX: %d new user-ids\n"), + (ulong)keyid[1], n_uids ); + if( n_sigs == 1 ) + log_info_f(fname, _("key %08lX: 1 new signature\n"), + (ulong)keyid[1]); + else if( n_sigs ) + log_info_f(fname, _("key %08lX: %d new signatures\n"), + (ulong)keyid[1], n_sigs ); + if( n_subk == 1 ) + log_info_f(fname, _("key %08lX: 1 new subkey\n"), + (ulong)keyid[1]); + else if( n_subk ) + log_info_f(fname, _("key %08lX: %d new subkeys\n"), + (ulong)keyid[1], n_subk ); + } + + stats.n_uids +=n_uids; + stats.n_sigs +=n_sigs; + stats.n_subk +=n_subk; + } + else { + if( !opt.quiet ) + log_info_f(fname, _("key %08lX: not changed\n"), + (ulong)keyid[1] ); + stats.unchanged++; } - else - log_info_f(fname, _("key %08lX: not changed\n"), (ulong)keyid[1] ); } - if( !rc ) { + if( !rc && !fast ) { rc = query_trust_record( new_key? pk : pk_orig ); if( rc && rc != -1 ) log_error("trustdb error: %s\n", g10_errstr(rc) ); @@ -399,7 +465,7 @@ import_one( const char *fname, KBNODE keyblock ) (ulong)keyid[1], g10_errstr(rc) ); } else if( mod_key ) - rc = update_trust_record( keyblock_orig ); + rc = update_trust_record( keyblock_orig, NULL ); else rc = clear_trust_checked_flag( new_key? pk : pk_orig ); } @@ -442,6 +508,7 @@ import_secret_one( const char *fname, KBNODE keyblock ) uidnode->pkt->pkt.user_id->len, 0 ); putc('\n', stderr); } + stats.secret_read++; if( !uidnode ) { log_error_f(fname, _("key %08lX: no user id\n"), (ulong)keyid[1]); return 0; @@ -468,10 +535,12 @@ import_secret_one( const char *fname, KBNODE keyblock ) unlock_keyblock( &kbpos ); /* we are ready */ log_info_f(fname, _("key %08lX: secret key imported\n"), (ulong)keyid[1]); + stats.secret_imported++; } else if( !rc ) { /* we can't merge secret keys */ log_error_f(fname, _("key %08lX: already in secret keyring\n"), (ulong)keyid[1]); + stats.secret_dups++; } else log_error_f(fname, _("key %08lX: secret key not found: %s\n"), @@ -569,8 +638,10 @@ import_revoke_cert( const char *fname, KBNODE node ) _("can't write keyblock: %s\n"), g10_errstr(rc) ); unlock_keyblock( &kbpos ); /* we are ready */ - log_info_f(fname, _("key %08lX: revocation certificate imported\n"), + if( !opt.quiet ) + log_info_f(fname, _("key %08lX: revocation certificate imported\n"), (ulong)keyid[1]); + stats.n_revoc++; leave: release_kbnode( keyblock ); diff --git a/g10/keyedit.c b/g10/keyedit.c index a504d06c7..62921349c 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -571,10 +571,12 @@ keyedit_menu( const char *username, STRLIST locusr ) tty_printf("\n"); redisplay = 0; } - m_free(answer); - answer = cpr_get(N_("keyedit.cmd"), _("Command> ")); - cpr_kill_prompt(); - trim_spaces(answer); + do { + m_free(answer); + answer = cpr_get(N_("keyedit.cmd"), _("Command> ")); + cpr_kill_prompt(); + trim_spaces(answer); + } while( *answer == '#' ); arg_number = 0; if( !*answer ) @@ -645,7 +647,7 @@ keyedit_menu( const char *username, STRLIST locusr ) } else tty_printf(_("Key not changed so no update needed.\n")); - rc = update_trust_record( keyblock ); + rc = update_trust_record( keyblock, NULL ); if( rc ) log_error(_("update of trust db failed: %s\n"), g10_errstr(rc) ); @@ -703,7 +705,7 @@ keyedit_menu( const char *username, STRLIST locusr ) sec_modified = modified = 1; /* must update the trustdb already here, so that preferences * get listed correctly */ - rc = update_trust_record( keyblock ); + rc = update_trust_record( keyblock, NULL ); if( rc ) { log_error(_("update of trust db failed: %s\n"), g10_errstr(rc) ); diff --git a/g10/main.h b/g10/main.h index 7cde3c58a..ddf7086e9 100644 --- a/g10/main.h +++ b/g10/main.h @@ -88,6 +88,7 @@ int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ); int overwrite_filep( const char *fname ); int open_outfile( const char *iname, int mode, IOBUF *a ); IOBUF open_sigfile( const char *iname ); +void copy_options_file( const char *destdir ); /*-- seskey.c --*/ void make_session_key( DEK *dek ); @@ -100,7 +101,7 @@ KBNODE make_comment_node( const char *s ); KBNODE make_mpi_comment_node( const char *s, MPI a ); /*-- import.c --*/ -int import_keys( const char *filename ); +int import_keys( const char *filename, int fast ); /*-- export.c --*/ int export_pubkeys( STRLIST users ); int export_seckeys( STRLIST users ); diff --git a/g10/mainproc.c b/g10/mainproc.c index 7980c22dc..a075f836f 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -180,11 +180,12 @@ proc_pubkey_enc( CTX c, PACKET *pkt ) if( is_ELGAMAL(enc->pubkey_algo) || enc->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA(enc->pubkey_algo) ) { - m_free(c->dek ); /* paranoid: delete a pending DEK */ - c->dek = m_alloc_secure( sizeof *c->dek ); - if( (result = get_session_key( enc, c->dek )) ) { - /* error: delete the DEK */ - m_free(c->dek); c->dek = NULL; + if ( !c->dek ) { + c->dek = m_alloc_secure( sizeof *c->dek ); + if( (result = get_session_key( enc, c->dek )) ) { + /* error: delete the DEK */ + m_free(c->dek); c->dek = NULL; + } } } else @@ -716,13 +717,6 @@ do_proc_packets( CTX c, IOBUF a ) c->iobuf = a; init_packet(pkt); while( (rc=parse_packet(a, pkt)) != -1 ) { - /* cleanup if we have an illegal data structure */ - if( c->dek && pkt->pkttype != PKT_ENCRYPTED ) { - /* FIXME: do we need to ave it in case we have no secret - * key for one of the next reciepents- we should check it - * here. */ - m_free(c->dek); c->dek = NULL; /* burn it */ - } if( rc ) { free_packet(pkt); diff --git a/g10/openfile.c b/g10/openfile.c index 763ac2f9a..0dff81bac 100644 --- a/g10/openfile.c +++ b/g10/openfile.c @@ -78,11 +78,11 @@ open_outfile( const char *iname, int mode, IOBUF *a ) *a = NULL; if( (!iname || (*iname=='-' && !iname[1])) && !opt.outfile ) { if( !(*a = iobuf_create(NULL)) ) { - log_error("can't open [stdout]: %s\n", strerror(errno) ); + log_error(_("%s: can't open: %s\n"), "[stdout]", strerror(errno) ); rc = G10ERR_CREATE_FILE; } else if( opt.verbose ) - log_info("writing to stdout\n"); + log_info(_("writing to stdout\n")); } else { char *buf=NULL; @@ -98,11 +98,11 @@ open_outfile( const char *iname, int mode, IOBUF *a ) } if( overwrite_filep( name ) ) { if( !(*a = iobuf_create( name )) ) { - log_error("can't create %s: %s\n", name, strerror(errno) ); + log_error(_("%s: can't create: %s\n"), name, strerror(errno) ); rc = G10ERR_CREATE_FILE; } else if( opt.verbose ) - log_info("writing to '%s'\n", name ); + log_info(_("writing to '%s'\n"), name ); } else rc = G10ERR_FILE_EXISTS; @@ -131,10 +131,54 @@ open_sigfile( const char *iname ) buf[len-4] = 0 ; a = iobuf_open( buf ); if( opt.verbose ) - log_info("assuming signed data in '%s'\n", buf ); + log_info(_("assuming signed data in '%s'\n"), buf ); m_free(buf); } } return a; } + +/**************** + * Copy the option file skeleton to the given directory. + */ +void +copy_options_file( const char *destdir ) +{ + const char *datadir = GNUPG_DATADIR; + char *fname; + FILE *src, *dst; + int linefeeds=0; + int c; + + fname = m_alloc( strlen(datadir) + strlen(destdir) + 15 ); + strcpy(stpcpy(fname, datadir), "/options.skel" ); + src = fopen( fname, "r" ); + if( !src ) { + log_error(_("%s: can't open: %s\n"), fname, strerror(errno) ); + m_free(fname); + return; + } + strcpy(stpcpy(fname, destdir), "/options" ); + dst = fopen( fname, "w" ); + if( !dst ) { + log_error(_("%s: can't create: %s\n"), fname, strerror(errno) ); + fclose( src ); + m_free(fname); + return; + } + + while( (c=getc(src)) != EOF ) { + if( linefeeds < 3 ) { + if( c == '\n' ) + linefeeds++; + } + else + putc( c, dst ); + } + fclose( dst ); + fclose( src ); + log_info(_("%s: new options file created\n"), fname ); + m_free(fname); +} + diff --git a/g10/options.h b/g10/options.h index 09a33016c..0ad465177 100644 --- a/g10/options.h +++ b/g10/options.h @@ -26,6 +26,7 @@ struct { int verbose; + int quiet; unsigned debug; int armor; int compress; diff --git a/g10/options.skel b/g10/options.skel new file mode 100644 index 000000000..009ce9d01 --- /dev/null +++ b/g10/options.skel @@ -0,0 +1,37 @@ +These first three lines are not copied to the options file in +the users home directory. +$Id$ +# Options for GnuPG +# +# Unless you you specify which option file to use (with the +# commandline option "--options filename"), GnuPG uses the +# file ~/.gnupg/options by default. +# +# An option file can contain all long options which are +# available in GnuPG. If the first non white space character of +# a line is a '#', this line is ignored. Empty lines are also +# ignored. +# +# See the man page for a list of options. + +# Uncomment the next line to get rid of the copyright notice +#no-greeting + +# If you have more than 1 secret key in your keyring, you may want +# to uncomment the following option and set your preffered keyid + +# default-key 621CC013 + +# The next option is enabled because this one is needed for interoperation +# with PGP 5 users. To enable full OpenPGP compliance you have to remove +# this option. + +force-v3-sigs + +# Default is to use the newer compress algo 2, but PGP 5 does not +# like this, so we use the old one +# Hmm: Do we really need this ... preferences should decide which compress +# algo to use. + +compress-algo 1 + diff --git a/g10/ringedit.c b/g10/ringedit.c index e414d0513..c7d1d8bb5 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -59,6 +59,7 @@ #include "keydb.h" #include "host2net.h" #include "options.h" +#include "main.h" #include "i18n.h" @@ -153,7 +154,7 @@ add_keyblock_resource( const char *url, int force, int secret ) { static int any_secret, any_public; const char *resname = url; - IOBUF iobuf; + IOBUF iobuf = NULL; int i; char *filename = NULL; int rc = 0; @@ -217,6 +218,8 @@ add_keyblock_resource( const char *url, int force, int secret ) else rt = rt_RING; } + else /* maybe empty: assume ring */ + rt = rt_RING; fclose( fp ); } else /* no file yet: create ring */ @@ -258,6 +261,7 @@ add_keyblock_resource( const char *url, int force, int secret ) } else log_info( _("%s: directory created\n"), filename ); + copy_options_file( filename ); } else { @@ -513,6 +517,7 @@ locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret ) rc = do_gdbm_locate( rentry->dbf, kbpos, fpr, fprlen ); break; default: + rc = G10ERR_UNSUPPORTED; break; } @@ -521,7 +526,7 @@ locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret ) kbpos->fp = NULL; return 0; } - else if( rc != -1 ) { + else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) { log_error("error searching resource %d: %s\n", i, g10_errstr(rc)); last_rc = rc; @@ -551,6 +556,7 @@ locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, int shortkid, int secret ) rc = do_gdbm_locate_by_keyid( rentry->dbf, kbpos, keyid ); break; default: + rc = G10ERR_UNSUPPORTED; break; } @@ -559,7 +565,7 @@ locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, int shortkid, int secret ) kbpos->fp = NULL; return 0; } - else if( rc != -1 ) { + else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) { log_error("error searching resource %d: %s\n", i, g10_errstr(rc)); last_rc = rc; @@ -719,7 +725,10 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) break; case rt_GDBM: break; - default: BUG(); + default: + log_error("OOPS in close enum_keyblocks - ignored\n"); + return rc; + break; } /* release pending packet */ free_packet( kbpos->pkt ); @@ -778,7 +787,8 @@ delete_keyblock( KBPOS *kbpos ) break; #ifdef HAVE_LIBGDBM case rt_GDBM: - /* FIXME!!!! */ + log_debug("deleting gdbm keyblock is not yet implemented\n"); + rc = 0; break; #endif default: BUG(); diff --git a/g10/sign.c b/g10/sign.c index 1f4e1ce65..db5272e53 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -253,7 +253,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, int skcount=0; /* loop over the secret certificates and build headers * The specs now say that the data should be bracket by - * the onepass-sig and signature-packet; so we muts build it + * the onepass-sig and signature-packet; so we must build it * here in reverse order */ for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) skcount++; @@ -320,10 +320,11 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, } else { if( fname || opt.set_filename ) { - const char *s = opt.set_filename ? opt.set_filename : fname; + char *s = make_basename( opt.set_filename ? opt.set_filename : fname ); pt = m_alloc( sizeof *pt + strlen(s) - 1 ); pt->namelen = strlen(s); memcpy(pt->name, s, pt->namelen ); + m_free(s); } else { /* no filename */ pt = m_alloc( sizeof *pt - 1 ); diff --git a/g10/tdbio.c b/g10/tdbio.c index 76e606e0e..1954929ae 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -56,9 +56,11 @@ struct cache_ctrl_struct { char data[TRUST_RECORD_LEN]; }; -#define MAX_CACHE_ENTRIES 200 +#define MAX_CACHE_ENTRIES_SOFT 200 /* may be increased due while in a */ +#define MAX_CACHE_ENTRIES_HARD 1000 /* transaction to this one */ static CACHE_CTRL cache_list; static int cache_entries; +static int cache_is_dirty; /* a type used to pass infomation to cmp_krec_fpr */ struct cmp_krec_fpr_struct { @@ -76,6 +78,7 @@ struct cmp_sdir_struct { static char *db_name; static int db_fd = -1; +static int in_transaction; static void open_db(void); @@ -143,8 +146,10 @@ put_record_into_cache( ulong recno, const char *data ) else if( r->recno == recno ) { if( !r->flags.dirty ) { /* Hmmm: should we use a a copy and compare? */ - if( memcmp(r->data, data, TRUST_RECORD_LEN ) ) + if( memcmp(r->data, data, TRUST_RECORD_LEN ) ) { r->flags.dirty = 1; + cache_is_dirty = 1; + } } memcpy( r->data, data, TRUST_RECORD_LEN ); return 0; @@ -163,11 +168,12 @@ put_record_into_cache( ulong recno, const char *data ) r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; + cache_is_dirty = 1; cache_entries++; return 0; } /* see whether we reached the limit */ - if( cache_entries < MAX_CACHE_ENTRIES ) { /* no */ + if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */ r = m_alloc( sizeof *r ); r->flags.used = 1; r->recno = recno; @@ -175,6 +181,7 @@ put_record_into_cache( ulong recno, const char *data ) r->flags.dirty = 1; r->next = cache_list; cache_list = r; + cache_is_dirty = 1; cache_entries++; return 0; } @@ -199,10 +206,31 @@ put_record_into_cache( ulong recno, const char *data ) r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; + cache_is_dirty = 1; cache_entries++; return 0; } /* no clean entries: have to flush some dirty entries */ + if( in_transaction ) { + /* but we can't do this while in a transaction + * we increase the cache size instead */ + if( cache_entries < MAX_CACHE_ENTRIES_HARD ) { /* no */ + if( !(cache_entries % 100) ) + log_info("increasing tdbio cache size\n"); + r = m_alloc( sizeof *r ); + r->flags.used = 1; + r->recno = recno; + memcpy( r->data, data, TRUST_RECORD_LEN ); + r->flags.dirty = 1; + r->next = cache_list; + cache_list = r; + cache_is_dirty = 1; + cache_entries++; + return 0; + } + log_info("hard cache size limit reached\n"); + return G10ERR_RESOURCE_LIMIT; + } if( dirty_count ) { int n = dirty_count / 5; /* discard some dirty entries */ if( !n ) @@ -226,6 +254,7 @@ put_record_into_cache( ulong recno, const char *data ) r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; + cache_is_dirty = 1; cache_entries++; return 0; } @@ -233,16 +262,27 @@ put_record_into_cache( ulong recno, const char *data ) } +int +tdbio_is_dirty() +{ + return cache_is_dirty; +} + /**************** - * Sync the cache to disk + * Flush the cache. This cannot be used while in a transaction. */ - int tdbio_sync() { CACHE_CTRL r; + if( in_transaction ) + log_bug("tdbio: syncing while in transaction\n"); + + if( !cache_is_dirty ) + return 0; + for( r = cache_list; r; r = r->next ) { if( r->flags.used && r->flags.dirty ) { int rc = write_cache_item( r ); @@ -250,6 +290,63 @@ tdbio_sync() return rc; } } + cache_is_dirty = 0; + return 0; +} + + + +/**************** + * Simple transactions system: + * Everything between begin_transaction and end/cancel_transaction + * is not immediatly written but at the time of end_transaction. + * + */ +int +tdbio_begin_transaction() +{ + int rc; + + if( in_transaction ) + log_bug("tdbio: nested transactions\n"); + /* flush everything out */ + rc = tdbio_sync(); + if( rc ) + return rc; + in_transaction = 1; + return 0; +} + +int +tdbio_end_transaction() +{ + if( !in_transaction ) + log_bug("tdbio: no active transaction\n"); + in_transaction = 0; + return tdbio_sync(); +} + +int +tdbio_cancel_transaction() +{ + CACHE_CTRL r; + + if( !in_transaction ) + log_bug("tdbio: no active transaction\n"); + + /* remove all dirty marked entries, so that the original ones + * are read back the next time */ + if( cache_is_dirty ) { + for( r = cache_list; r; r = r->next ) { + if( r->flags.used && r->flags.dirty ) { + r->flags.used = 0; + cache_entries--; + } + } + cache_is_dirty = 0; + } + + in_transaction = 0; return 0; } @@ -293,6 +390,7 @@ tdbio_set_dbname( const char *new_dbname, int create ) fname, strerror(errno) ); else log_info( _("%s: directory created\n"), fname ); + copy_options_file( fname ); } else log_fatal( _("%s: directory does not exist!\n"), fname ); diff --git a/g10/tdbio.h b/g10/tdbio.h index 68011d48f..e44f8c3e4 100644 --- a/g10/tdbio.h +++ b/g10/tdbio.h @@ -168,7 +168,11 @@ const char *tdbio_get_dbname(void); 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_is_dirty(void); int tdbio_sync(void); +int tdbio_begin_transaction(void); +int tdbio_end_transaction(void); +int tdbio_cancel_transaction(void); int tdbio_delete_record( ulong recnum ); ulong tdbio_new_recnum(void); int tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec ); diff --git a/g10/trustdb.c b/g10/trustdb.c index 5f391d028..7a6ec3bd1 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -65,7 +65,7 @@ struct trust_info { typedef struct trust_seg_list *TRUST_SEG_LIST; struct trust_seg_list { TRUST_SEG_LIST next; - int nseg; /* number of segmens */ + int nseg; /* number of segments */ int dup; TRUST_INFO seg[1]; /* segment list */ }; @@ -86,14 +86,9 @@ static LOCAL_ID_INFO *new_lid_table(void); static void release_lid_table( LOCAL_ID_INFO *tbl ); static int ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag ); static int qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag ); -static void upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag ); static void print_user_id( const char *text, u32 *keyid ); -static int do_list_path( TRUST_INFO *stack, int depth, int max_depth, - LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist ); - static int list_sigs( ulong pubkey_id ); -static int propagate_trust( TRUST_SEG_LIST tslist ); static int do_check( TRUSTREC *drec, unsigned *trustlevel ); static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec ); @@ -102,8 +97,6 @@ static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec ); * which are the ones from our secrings */ static LOCAL_ID_INFO *ultikey_table; -static ulong last_trust_web_key; -static TRUST_SEG_LIST last_trust_web_tslist; #define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \ @@ -277,19 +270,6 @@ qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag ) return -1; } -static void -upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag ) -{ - LOCAL_ID_INFO a; - - for( a = tbl[lid & 0x0f]; a; a = a->next ) - if( a->lid == lid ) { - a->flag = flag; - return; - } - BUG(); -} - /**************** @@ -301,12 +281,19 @@ keyid_from_lid( ulong lid, u32 *keyid ) TRUSTREC rec; int rc; - rc = tdbio_read_record( lid, &rec, RECTYPE_DIR ); + rc = tdbio_read_record( lid, &rec, 0 ); if( rc ) { log_error("error reading dir record for LID %lu: %s\n", lid, g10_errstr(rc)); return G10ERR_TRUSTDB; } + if( rec.rectype == RECTYPE_SDIR ) + return 0; + if( rec.rectype != RECTYPE_DIR ) { + log_error("lid %lu: expected dir record, got type %d\n", + lid, rec.rectype ); + return G10ERR_TRUSTDB; + } if( !rec.r.dir.keylist ) { log_error("no primary key for LID %lu\n", lid ); return G10ERR_TRUSTDB; @@ -342,7 +329,6 @@ lid_from_keyblock( KBNODE keyblock ) - /**************** * Walk through the signatures of a public key. * The caller must provide a context structure, with all fields set @@ -364,9 +350,13 @@ walk_sigrecs( SIGREC_CONTEXT *c ) r = &c->ctl.rec; if( !c->ctl.init_done ) { c->ctl.init_done = 1; - read_record( c->lid, r, RECTYPE_DIR ); + 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 (what a bad bad hack) */ + /* force a read */ c->ctl.index = SIGS_PER_RECORD; r->r.sig.next = 0; } @@ -503,17 +493,18 @@ print_user_id( const char *text, u32 *keyid ) m_free(p); } -static void + +static int print_keyid( FILE *fp, ulong lid ) { u32 ki[2]; if( keyid_from_lid( lid, ki ) ) - fprintf(fp, "????????.%lu", lid ); + return fprintf(fp, "????????.%lu", lid ); else - fprintf(fp, "%08lX.%lu", (ulong)ki[1], lid ); + return fprintf(fp, "%08lX.%lu", (ulong)ki[1], lid ); } -static void +static int print_trust( FILE *fp, unsigned trust ) { int c; @@ -525,14 +516,32 @@ print_trust( FILE *fp, unsigned trust ) case TRUST_MARGINAL: c = 'm'; break; case TRUST_FULLY: c = 'f'; break; case TRUST_ULTIMATE: c = 'u'; break; - default: fprintf(fp, "%02x", trust ); return; + default: fprintf(fp, "%02x", trust ); return 2; } putc(c, fp); + return 1; +} + + +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 pubkey, int depth, +do_list_sigs( ulong root, ulong pk_lid, int depth, LOCAL_ID_INFO *lids, unsigned *lineno ) { SIGREC_CONTEXT sx; @@ -540,26 +549,29 @@ do_list_sigs( ulong root, ulong pubkey, int depth, u32 keyid[2]; memset( &sx, 0, sizeof sx ); - sx.lid = pubkey; + sx.lid = pk_lid; for(;;) { rc = walk_sigrecs( &sx ); if( rc ) break; rc = keyid_from_lid( sx.sig_lid, keyid ); if( rc ) { - printf("%6u: %*s????????.%lu:%02x\n", *lineno, depth*4, "", - sx.sig_lid, sx.sig_flag ); + 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:%02x ", *lineno, depth*4, "", - (ulong)keyid[1], sx.sig_lid, sx.sig_flag ); - /* check whether we already checked this pubkey */ + 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 == pubkey ) { + else if( sx.sig_lid == pk_lid ) { printf("[self-signature]\n"); ++*lineno; } @@ -632,7 +644,7 @@ list_records( ulong lid ) tdbio_dump_record( &dr, stdout ); for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) { - rc = tdbio_read_record( recno, &rec, RECTYPE_KEY ); + rc = tdbio_read_record( recno, &rec, 0 ); if( rc ) { log_error("lid %lu: read key record failed: %s\n", lid, g10_errstr(rc)); @@ -681,197 +693,241 @@ list_records( ulong lid ) /**************** - * Function to collect all trustpaths + * 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 -do_list_path( TRUST_INFO *stack, int depth, int max_depth, - LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist ) +verify_key( int depth, int max_depth, TRUSTREC *drec ) { - SIGREC_CONTEXT sx; - unsigned last_depth; - int rc; + ulong rn, uidrn; + int marginal=0; + int fully=0; + size_t dbglen; + + /* Note: If used stack size is an issue, we could reuse the + * trustrec vars and reread them as needed */ + + dbglen = printf("verify_key: depth=%d %*s", depth, depth*3,"" ); + dbglen += print_keyid( stdout, drec->recnum ); + dbglen += printf(" ot="); + dbglen += print_trust(stdout, drec->r.dir.ownertrust ); + dbglen += printf(" -> "); + + if( depth >= max_depth ) { + /* max cert_depth reached */ + puts("undefined (too deep)"); + return TRUST_UNDEFINED; + } + if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) { + /* we are at the end of a path */ + puts("ultimate"); + return TRUST_ULTIMATE; + } + + /* loop over all user-ids */ + for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) { + TRUSTREC rec; /* used for uids and sigs */ + ulong sigrn; + + read_record( rn, &rec, RECTYPE_UID ); + uidrn = rec.r.uid.next; + /* fixme: continue if the uidrec is not marked valid */ + + /* loop over all signature records */ + for( rn = rec.r.uid.siglist; rn; rn = sigrn ) { + int i; - assert(depth); + read_record( rn, &rec, RECTYPE_SIG ); + sigrn = rec.r.sig.next; - /*printf("%2lu/%d: scrutinizig\n", stack[depth-1], depth);*/ - if( depth >= max_depth || depth >= MAX_LIST_SIGS_DEPTH-1 ) { - /*printf("%2lu/%d: too deeply nested\n", stack[depth-1], depth);*/ - return 0; - } - memset( &sx, 0, sizeof sx ); - sx.lid = stack[depth-1].lid; - /* loop over all signatures. If we do not have any, try to create them */ - while( !(rc = walk_sigrecs( &sx )) ) { - TRUST_SEG_LIST tsl, t2, tl; - int i; + for(i=0; i < SIGS_PER_RECORD; i++ ) { + TRUSTREC tmp; + int ot, nt; - if( !(sx.sig_flag & SIGF_CHECKED) ) - continue; /* only checked sigs */ - if( !(sx.sig_flag & SIGF_VALID) ) - continue; /* and, of course, only valid sigs */ - if( (sx.sig_flag & SIGF_REVOKED) ) - continue; /* and skip revoked sigs */ - - stack[depth].lid = sx.sig_lid; - stack[depth].trust = 0; - if( qry_lid_table_flag( lids, sx.sig_lid, &last_depth) ) { - /*printf("%2lu/%d: marked\n", sx.sig_lid, depth );*/ - ins_lid_table_item( lids, sx.sig_lid, depth); - last_depth = depth; - } - else if( depth < last_depth ) { - /*printf("%2lu/%d: last_depth=%u - updated\n", sx.sig_lid, depth, last_depth);*/ - last_depth = depth; - upd_lid_table_flag( lids, sx.sig_lid, depth); - } + if( !rec.r.sig.sig[i].lid ) + continue; /* skip deleted sigs */ + if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) ) + continue; /* skip unchecked signatures */ + if( !(rec.r.sig.sig[i].flag & SIGF_VALID) ) + continue; /* skip invalid signatures */ + if( (rec.r.sig.sig[i].flag & SIGF_EXPIRED) ) + continue; /* skip expired signatures */ + if( (rec.r.sig.sig[i].flag & SIGF_REVOKED) ) + continue; /* skip revoked signatures */ + /* fixme: skip duplicates */ + + read_record( rec.r.sig.sig[i].lid, &tmp, RECTYPE_DIR ); + ot = tmp.r.dir.ownertrust & TRUST_MASK; + #if 0 /* Does not work, because the owner trust of our + * own keys is not always set + * -- fix this in verify_own_keys() ? */ + if( ot < TRUST_MARGINAL ) { + printf(". "); + continue; /* ownertrust is too low; don't need to check */ + } + #endif + if( ot >= TRUST_FULLY ) + ot = TRUST_FULLY; /* just in case */ + + puts(""); + nt = verify_key( depth+1, max_depth, &tmp ) & TRUST_MASK; + if( nt < TRUST_MARGINAL ) { + printf("%*s* ", dbglen, ""); + dbglen += 2; + continue; + } - if( last_depth < depth ) - /*printf("%2lu/%d: already visited\n", sx.sig_lid, depth)*/; - else if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) { - /* found end of path; store it, ordered by path length */ - tsl = m_alloc( sizeof *tsl + depth*sizeof(TRUST_INFO) ); - tsl->nseg = depth+1; - tsl->dup = 0; - for(i=0; i <= depth; i++ ) - tsl->seg[i] = stack[i]; - for(t2=*tslist,tl=NULL; t2; tl=t2, t2 = t2->next ) - if( depth < t2->nseg ) - break; - if( !tl ) { - tsl->next = t2; - *tslist = tsl; - } - else { - tsl->next = t2; - tl->next = tsl; + if( nt == TRUST_ULTIMATE ) { + /* we have signed this key and only in this special case + * we assume a completes-needed or marginals-needed of 1 */ + printf("%*s", dbglen, ""); + if( ot == TRUST_MARGINAL ) + puts("marginal (1st level)"); + else if( ot == TRUST_FULLY ) + puts("fully (1st level)"); + else + puts("????? (1st level)"); + return ot; + } + + if( nt >= TRUST_FULLY ) + fully++; + if( nt >= TRUST_MARGINAL ) + marginal++; + + if( fully >= opt.completes_needed + || marginal >= opt.marginals_needed ) { + printf("%*s", dbglen, ""); + puts("fully"); + return TRUST_FULLY; + } } - /*putchar('.'); fflush(stdout);*/ - /*printf("%2lu/%d: found\n", sx.sig_lid, depth);*/ - } - else { - rc = do_list_path( stack, depth+1, max_depth, lids, tslist); - if( rc && rc != -1 ) - break; } } - return rc==-1? 0 : rc; + printf("%*s", dbglen, ""); + if( marginal ) { + puts("marginal"); + return TRUST_MARGINAL; + } + puts("undefined"); + return TRUST_UNDEFINED; } -/**************** - * Make a list of trust paths - */ static int -make_tsl( ulong lid, TRUST_SEG_LIST *ret_tslist ) +list_paths( int depth, int max_depth, TRUSTREC *drec ) { - int i, rc; - LOCAL_ID_INFO *lids = new_lid_table(); - TRUST_INFO stack[MAX_LIST_SIGS_DEPTH]; - TRUST_SEG_LIST tsl, tslist; - int max_depth = 4; - - tslist = *ret_tslist = NULL; - - if( !qry_lid_table_flag( ultikey_table, lid, NULL ) ) { - tslist = m_alloc( sizeof *tslist ); - tslist->nseg = 1; - tslist->dup = 0; - tslist->seg[0].lid = lid; - tslist->seg[0].trust = 0; - tslist->next = NULL; - rc = 0; + ulong rn, uidrn; + int marginal=0; + int fully=0; + size_t dbglen; + + if( depth >= max_depth ) { + /* max cert_depth reached */ + puts("undefined (too deep)"); + return TRUST_UNDEFINED; } - else { - stack[0].lid = lid; - stack[0].trust = 0; - rc = do_list_path( stack, 1, max_depth, lids, &tslist ); - } - if( !rc ) { /* wipe out duplicates */ - LOCAL_ID_INFO *work = new_lid_table(); - for( tsl=tslist; tsl; tsl = tsl->next ) { - for(i=1; i < tsl->nseg-1; i++ ) { - if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) { - tsl->dup = 1; /* mark as duplicate */ - break; - } - } - } - release_lid_table(work); - *ret_tslist = tslist; - } - else { /* error: release tslist */ - while( tslist ) { - tsl = tslist->next; - m_free(tslist); - tslist = tsl; - } + if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) { + /* we are at the end of a path */ + puts("ultimate"); + return TRUST_ULTIMATE; } - release_lid_table(lids); - return rc; -} + /* loop over all user-ids */ + for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) { + TRUSTREC rec; /* used for uids and sigs */ + ulong sigrn; -/**************** - * Given a trust segment list tslist, walk over all paths and fill in - * the trust information for each segment. What this function does is - * to assign a trustvalue to the first segment (which is the requested key) - * of each path. - * - * FIXME: We have to do more thinking here. e.g. we should never increase - * the trust value. - * - * Do not do it for duplicates. - */ -static int -propagate_trust( TRUST_SEG_LIST tslist ) -{ - int i; - unsigned trust, tr; - TRUST_SEG_LIST tsl; + read_record( rn, &rec, RECTYPE_UID ); + uidrn = rec.r.uid.next; + /* fixme: continue if the uidrec is not marked valid */ - for(tsl = tslist; tsl; tsl = tsl->next ) { - if( tsl->dup ) - continue; - assert( tsl->nseg ); - /* the last segment is always an ultimately trusted one, so we can - * assign a fully trust to the next one */ - i = tsl->nseg-1; - tsl->seg[i].trust = TRUST_ULTIMATE; - trust = TRUST_FULLY; - for(i-- ; i >= 0; i-- ) { - tsl->seg[i].trust = trust; - if( i > 0 ) { - /* get the trust of this pubkey */ - tr = get_ownertrust( tsl->seg[i].lid ); - if( tr < trust ) - trust = tr; + /* loop over all signature records */ + for( rn = rec.r.uid.siglist; rn; rn = sigrn ) { + int i; + + read_record( rn, &rec, RECTYPE_SIG ); + sigrn = rec.r.sig.next; + + for(i=0; i < SIGS_PER_RECORD; i++ ) { + TRUSTREC tmp; + int ot, nt; + + if( !rec.r.sig.sig[i].lid ) + continue; /* skip deleted sigs */ + if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) ) + continue; /* skip unchecked signatures */ + if( !(rec.r.sig.sig[i].flag & SIGF_VALID) ) + continue; /* skip invalid signatures */ + if( (rec.r.sig.sig[i].flag & SIGF_EXPIRED) ) + continue; /* skip expired signatures */ + if( (rec.r.sig.sig[i].flag & SIGF_REVOKED) ) + continue; /* skip revoked signatures */ + /* fixme: skip duplicates */ + + read_record( rec.r.sig.sig[i].lid, &tmp, RECTYPE_DIR ); + ot = tmp.r.dir.ownertrust & TRUST_MASK; + if( ot < TRUST_MARGINAL ) { + printf(". "); + continue; /* ownertrust is too low; don't need to check */ + } + + if( ot >= TRUST_FULLY ) + ot = TRUST_FULLY; /* just in case */ + + puts(""); + nt = verify_key( depth+1, max_depth, &tmp ) & TRUST_MASK; + if( nt < TRUST_MARGINAL ) { + printf("%*s* ", dbglen, ""); + dbglen += 2; + continue; + } + + if( nt == TRUST_ULTIMATE ) { + /* we have signed this key and only in this special case + * we assume a completes-needed or marginals-needed of 1 */ + printf("%*s", dbglen, ""); + if( ot == TRUST_MARGINAL ) + puts("marginal (1st level)"); + else if( ot == TRUST_FULLY ) + puts("fully (1st level)"); + else + puts("????? (1st level)"); + return ot; + } + + if( nt >= TRUST_FULLY ) + fully++; + if( nt >= TRUST_MARGINAL ) + marginal++; + + if( fully >= opt.completes_needed + || marginal >= opt.marginals_needed ) { + printf("%*s", dbglen, ""); + puts("fully"); + return TRUST_FULLY; + } } } } - return 0; + printf("%*s", dbglen, ""); + if( marginal ) { + puts("marginal"); + return TRUST_MARGINAL; + } + puts("undefined"); + return TRUST_UNDEFINED; } /**************** * we have the pubkey record and all needed informations are in the trustdb * but nothing more is known. - * (this function may re-read the dir record dr) */ static int do_check( TRUSTREC *dr, unsigned *trustlevel ) { - int i, rc=0; - TRUST_SEG_LIST tsl, tsl2, tslist; - int marginal, fully; - int fully_needed = opt.completes_needed; - int marginal_needed = opt.marginals_needed; - unsigned tflags = 0; - - assert( fully_needed > 0 && marginal_needed > 1 ); - - - *trustlevel = TRUST_UNDEFINED; - if( !dr->r.dir.keylist ) { log_error("Ooops, no keys\n"); return G10ERR_TRUSTDB; @@ -881,92 +937,15 @@ do_check( TRUSTREC *dr, unsigned *trustlevel ) return G10ERR_TRUSTDB; } - /* did we already check the signatures */ - /* fixme:.... */ + *trustlevel = verify_key( 1, 5, dr ); if( dr->r.dir.dirflags & DIRF_REVOKED ) - tflags |= TRUST_FLAG_REVOKED; - - #if 0 /* Do we still need this?? */ - if( !rc && !dr->r.dir.siglist ) { - /* We do not have any signatures; check whether it is one of our - * secret keys */ - if( !qry_lid_table_flag( ultikey_table, dr->r.dir.lid, NULL ) ) - *trustlevel = tflags | TRUST_ULTIMATE; - return 0; - } - #endif - if( rc ) - return rc; /* error while looking for sigrec or building sigrecs */ - - /* fixme: take it from the cache if it is valid */ + *trustlevel |= TRUST_FLAG_REVOKED; - /* Make a list of all possible trust-paths */ - rc = make_tsl( dr->r.dir.lid, &tslist ); - if( rc ) - return rc; - rc = propagate_trust( tslist ); - if( rc ) - return rc; - for(tsl = tslist; tsl; tsl = tsl->next ) { - if( tsl->dup ) - continue; - - if( opt.verbose ) { - log_info("trust path:" ); - for(i=0; i < tsl->nseg; i++ ) { - putc(' ',stderr); - print_keyid( stderr, tsl->seg[i].lid ); - putc(':',stderr); - print_trust( stderr, tsl->seg[i].trust ); - } - putc('\n',stderr); - } - } - - /* and see whether there is a trusted path. - * We only have to look at the first segment, because - * propagate_trust has investigated all other segments */ - marginal = fully = 0; - for(tsl = tslist; tsl; tsl = tsl->next ) { - if( tsl->dup ) - continue; - if( tsl->seg[0].trust == TRUST_ULTIMATE ) { - *trustlevel = tflags | TRUST_ULTIMATE; /* our own key */ - break; - } - if( tsl->seg[0].trust == TRUST_FULLY ) { - marginal++; - fully++; - } - else if( tsl->seg[0].trust == TRUST_MARGINAL ) - marginal++; - - if( fully >= fully_needed ) { - *trustlevel = tflags | TRUST_FULLY; - break; - } - } - if( !tsl && marginal >= marginal_needed ) - *trustlevel = tflags | TRUST_MARGINAL; - - /* cache the tslist */ - if( last_trust_web_key ) { - for( tsl = last_trust_web_tslist; tsl; tsl = tsl2 ) { - tsl2 = tsl->next; - m_free(tsl); - } - } - last_trust_web_key = dr->r.dir.lid; - last_trust_web_tslist = tslist; return 0; } -/*********************************************** - **************** API ************************ - ***********************************************/ - /**************** * Perform some checks over the trustdb * level 0: only open the db @@ -1059,6 +1038,9 @@ export_ownertrust() byte *p; int rc; + 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 ) { @@ -1184,7 +1166,6 @@ list_trust_path( int max_depth, const char *username ) { int rc; int wipe=0; - int i; TRUSTREC rec; PKT_public_key *pk = m_alloc_clear( sizeof *pk ); @@ -1192,6 +1173,8 @@ list_trust_path( int max_depth, const char *username ) wipe = 1; max_depth = -max_depth; } + if( max_depth < 1 ) + max_depth = 1; if( (rc = get_pubkey_byname( pk, username )) ) log_error("user '%s' not found: %s\n", username, g10_errstr(rc) ); @@ -1208,61 +1191,6 @@ list_trust_path( int max_depth, const char *username ) } } - if( !rc ) { - TRUST_SEG_LIST tsl, tslist = NULL; - - if( !qry_lid_table_flag( ultikey_table, pk->local_id, NULL ) ) { - tslist = m_alloc( sizeof *tslist ); - tslist->nseg = 1; - tslist->dup = 0; - tslist->seg[0].lid = pk->local_id; - tslist->seg[0].trust = 0; - tslist->next = NULL; - rc = 0; - } - else { - LOCAL_ID_INFO *lids = new_lid_table(); - TRUST_INFO stack[MAX_LIST_SIGS_DEPTH]; - - stack[0].lid = pk->local_id; - stack[0].trust = 0; - rc = do_list_path( stack, 1, max_depth, lids, &tslist ); - if( wipe ) { /* wipe out duplicates */ - LOCAL_ID_INFO *work; - - work = new_lid_table(); - for( tsl=tslist; tsl; tsl = tsl->next ) { - for(i=1; i < tsl->nseg-1; i++ ) { - if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) { - tsl->dup = 1; /* mark as duplicate */ - break; - } - } - } - release_lid_table(work); - } - release_lid_table(lids); - } - if( rc ) - log_error("user '%s' list problem: %s\n", username, g10_errstr(rc)); - rc = propagate_trust( tslist ); - if( rc ) - log_error("user '%s' trust problem: %s\n", username, g10_errstr(rc)); - for(tsl = tslist; tsl; tsl = tsl->next ) { - int i; - - if( tsl->dup ) - continue; - printf("trust path:" ); - for(i=0; i < tsl->nseg; i++ ) { - putc(' ',stdout); - print_keyid( stdout, tsl->seg[i].lid ); - putc(':',stdout); - print_trust( stdout, tsl->seg[i].trust ); - } - putchar('\n'); - } - } free_public_key( pk ); } @@ -1288,7 +1216,9 @@ check_trustdb( const char *username ) username, g10_errstr(rc)); } else { - rc = update_trust_record( keyblock ); + int modified; + + rc = update_trust_record( keyblock, &modified ); if( rc == -1 ) { /* not yet in trustdb: insert */ rc = insert_trust_record( find_kbnode( keyblock, PKT_PUBLIC_KEY @@ -1298,20 +1228,27 @@ check_trustdb( const char *username ) if( rc ) log_error("%s: update failed: %s\n", username, g10_errstr(rc) ); - else + 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; } @@ -1323,18 +1260,37 @@ check_trustdb( const char *username ) if( rc ) { log_error("lid %lu: keyblock not found: %s\n", recnum, g10_errstr(rc) ); + count++; + skip_count++; continue; } - rc = update_trust_record( keyblock ); - if( rc ) + + rc = update_trust_record( keyblock, &modified ); + if( rc ) { log_error("lid %lu: update failed: %s\n", recnum, g10_errstr(rc) ); - else - log_info("lid %lu: updated\n", recnum ); + 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); } } @@ -1348,31 +1304,57 @@ update_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 )) ) { - rc = update_trust_record( keyblock ); + int modified; + + rc = update_trust_record( keyblock, &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 ) + if( rc && !pk->local_id ) { log_error("lid ?: insert failed: %s\n", g10_errstr(rc) ); - else if( rc ) + err_count++; + } + else if( rc ) { log_error("lid %lu: insert failed: %s\n", pk->local_id, g10_errstr(rc) ); - else - log_info("lid %lu: inserted\n", pk->local_id ); + err_count++; + } + else { + if( opt.verbose ) + log_info("lid %lu: inserted\n", pk->local_id ); + new_count++; + } } - else if( rc ) + else if( rc ) { log_error("lid %lu: update failed: %s\n", lid_from_keyblock(keyblock), g10_errstr(rc) ); - else - log_info("lid %lu: updated\n", - lid_from_keyblock(keyblock) ); + 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("enum_keyblocks failed: %s\n", g10_errstr(rc)); @@ -1510,54 +1492,8 @@ query_trust_info( PKT_public_key *pk ) int enum_trust_web( void **context, ulong *lid ) { - struct { - TRUST_SEG_LIST tsl; - int index; - } *c = *context; - - if( !c ) { /* make a new context */ - c = m_alloc_clear( sizeof *c ); - *context = c; - if( *lid == last_trust_web_key && last_trust_web_tslist ) - c->tsl = last_trust_web_tslist; - else { - TRUST_SEG_LIST tsl, tsl2, tslist; - int rc; + /* REPLACE THIS with a BETTER ONE */ - rc = make_tsl( *lid, &tslist ); - if( rc ) { - log_error("failed to build the TSL\n"); - return rc; - } - /* cache the tslist, so that we do not need to free it */ - if( last_trust_web_key ) { - for( tsl = last_trust_web_tslist; tsl; tsl = tsl2 ) { - tsl2 = tsl->next; - m_free(tsl); - } - } - last_trust_web_key = *lid; - last_trust_web_tslist = tslist; - c->tsl = last_trust_web_tslist; - } - c->index = 1; - } - - if( !lid ) { /* free the context */ - m_free( c ); - *context = NULL; - return 0; - } - - while( c->tsl ) { - if( !c->tsl->dup && c->index < c->tsl->nseg-1 ) { - *lid = c->tsl->seg[c->index].lid; - c->index++; - return 0; - } - c->index = 1; - c->tsl = c->tsl->next; - } return -1; /* eof */ } @@ -1709,7 +1645,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash, TRUSTREC *sigrec, int sigidx, ulong hint_owner ) { KBNODE node; - int rc, state=0; + int rc, state; byte uhash[20]; int is_selfsig; PKT_signature *sigpkt = NULL; @@ -1743,6 +1679,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash, /* find the correct signature packet */ + state = 0; for( node=keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uidpkt = node->pkt->pkt.user_id; @@ -1757,13 +1694,19 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash, sigpkt = node->pkt->pkt.signature; if( sigpkt->keyid[0] == sigkid[0] && sigpkt->keyid[1] == sigkid[1] - && (sigpkt->sig_class&~3) == 0x10 ) + && (sigpkt->sig_class&~3) == 0x10 ) { + state = 2; break; /* found */ + } } } if( !node ) { - log_error(_("lid %lu: user id not found in keyblock\n"), lid ); + log_info(_("lid %lu: user id not found in keyblock\n"), lid ); + return ; + } + if( state != 2 ) { + log_info(_("lid %lu: user id without signature\n"), lid ); return ; } @@ -1776,7 +1719,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash, if( !rc ) { /* valid signature */ if( opt.verbose ) log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "good signature (3)\n"), + "Good signature (3)\n"), (ulong)keyid[1], lid, uhash[18], uhash[19], (ulong)sigpkt->keyid[1] ); sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID; @@ -1789,8 +1732,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash, sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY; } else { - log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "invalid signature: %s\n"), + log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: %s\n"), (ulong)keyid[1], lid, uhash[18], uhash[19], (ulong)sigpkt->keyid[1], g10_errstr(rc) ); sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED; @@ -1893,6 +1835,74 @@ process_hintlist( ulong hintlist, ulong hint_owner ) } +/**************** + * Create or update shadow dir record and return the LID of the record + */ +static ulong +create_shadow_dir( PKT_signature *sig, ulong lid ) +{ + TRUSTREC sdir, hlst, tmphlst; + ulong recno, newlid; + int tmpidx; + int rc; + + /* first see whether we already have such a record */ + rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir ); + if( rc && rc != -1 ) { + log_error("tdbio_search_dir failed: %s\n", g10_errstr(rc)); + die_invalid_db(); + } + if( rc == -1 ) { /* not found: create */ + memset( &sdir, 0, sizeof sdir ); + sdir.recnum = tdbio_new_recnum(); + sdir.rectype= RECTYPE_SDIR; + sdir.r.sdir.lid = sdir.recnum; + sdir.r.sdir.keyid[0] = sig->keyid[0]; + sdir.r.sdir.keyid[1] = sig->keyid[1]; + sdir.r.sdir.pubkey_algo = sig->pubkey_algo; + sdir.r.sdir.hintlist = 0; + write_record( &sdir ); + } + newlid = sdir.recnum; + /* Put the record number into the hintlist. + * (It is easier to use the lid and not the record number of the + * key to save some space (assuming that a signator has + * signed more than one user id - and it is easier to implement.) + */ + tmphlst.recnum = 0; + for( recno=sdir.r.sdir.hintlist; recno; recno = hlst.r.hlst.next) { + int i; + read_record( recno, &hlst, RECTYPE_HLST ); + for( i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { + if( !hlst.r.hlst.rnum[i] ) { + if( !tmphlst.recnum ) { + tmphlst = hlst; + tmpidx = i; + } + } + else if( hlst.r.hlst.rnum[i] == lid ) + return newlid; /* the signature is already in the hintlist */ + } + } + /* not yet in the hint list, write it */ + if( tmphlst.recnum ) { /* we have an empty slot */ + tmphlst.r.hlst.rnum[tmpidx] = lid; + write_record( &tmphlst ); + } + else { /* must append a new hlst record */ + memset( &hlst, 0, sizeof hlst ); + hlst.recnum = tdbio_new_recnum(); + hlst.rectype = RECTYPE_HLST; + hlst.r.hlst.next = sdir.r.sdir.hintlist; + hlst.r.hlst.rnum[0] = lid; + write_record( &hlst ); + sdir.r.sdir.hintlist = hlst.recnum; + write_record( &sdir ); + } + + return newlid; +} + static void upd_key_record( PKT_public_key *pk, TRUSTREC *drec, RECNO_LIST *recno_list ) @@ -1941,7 +1951,7 @@ upd_key_record( PKT_public_key *pk, TRUSTREC *drec, RECNO_LIST *recno_list ) static void upd_uid_record( PKT_user_id *uid, TRUSTREC *drec, RECNO_LIST *recno_list, - u32 *keyid, ulong *uidrecno, byte *uidhash ) + u32 *keyid, ulong *uidrecno, byte *uidhash ) { TRUSTREC urec; ulong recno, newrecno; @@ -1981,8 +1991,8 @@ upd_uid_record( PKT_user_id *uid, TRUSTREC *drec, RECNO_LIST *recno_list, static void -upd_pref_record( PKT_signature *sig, TRUSTREC *drec, - u32 *keyid, TRUSTREC *urec, byte *uidhash ) +upd_pref_record( PKT_signature *sig, ulong lid, const u32 *keyid, + TRUSTREC *urec, const byte *uidhash ) { static struct { sigsubpkttype_t subpkttype; @@ -2003,7 +2013,8 @@ upd_pref_record( PKT_signature *sig, TRUSTREC *drec, /* First delete all pref records * This is much simpler than checking whether we have to - * do update the record at all - the record cache may care about it */ + * do update the record at all - the record cache may care about it + * FIXME: We never get correct statistics if we di it like this */ for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) { read_record( recno, &prec, RECTYPE_PREF ); delete_record( recno ); @@ -2027,7 +2038,7 @@ upd_pref_record( PKT_signature *sig, TRUSTREC *drec, } memset( &prec, 0, sizeof prec ); prec.rectype = RECTYPE_PREF; - prec.r.pref.lid = drec->recnum; + prec.r.pref.lid = lid; i = 0; } prec.r.pref.data[i++] = prefs[k].preftype; @@ -2053,6 +2064,248 @@ upd_pref_record( PKT_signature *sig, TRUSTREC *drec, } +/**************** + * update self key signatures (class 0x10..0x13) + */ +static void +upd_self_key_sigs( PKT_signature *sig, TRUSTREC *urec, + ulong lid, const u32 *keyid, const byte *uidhash, + KBNODE keyblock, KBNODE signode) +{ + int rc; + + /* must verify this selfsignature here, so that we can + * build the preference record and validate the uid record + */ + if( !(urec->r.uid.uidflags & UIDF_CHECKED) ) { + rc = check_key_signature( keyblock, signode, NULL ); + if( !rc ) { + if( opt.verbose ) + log_info(_( + "key %08lX.%lu, uid %02X%02X: Good self-signature\n"), + (ulong)keyid[1], lid, uidhash[18], uidhash[19] ); + upd_pref_record( sig, lid, keyid, urec, uidhash ); + urec->r.uid.uidflags = UIDF_CHECKED | UIDF_VALID; + } + else { + log_info(_("key %08lX, uid %02X%02X: Invalid self-signature: %s\n"), + (ulong)keyid[1], uidhash[18], uidhash[19], g10_errstr(rc) ); + urec->r.uid.uidflags = UIDF_CHECKED; + } + urec->dirty = 1; + } +} + + +/**************** + * update non-self key signatures (class 0x10..0x13) + */ +static void +upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec, + ulong lid, const u32 *keyid, const byte *uidhash, + KBNODE keyblock, KBNODE signode) +{ + /* We simply insert the signature into the sig records but + * avoid duplicate ones. We do not check them here because + * there is a big chance, that we import required public keys + * later. The problem with this is that we must somewhere store + * the information about this signature (we need a record id). + * We do this by using the record type shadow dir, which will + * be converted to a dir record as soon as a new public key is + * inserted into the trustdb. + */ + TRUSTREC rec; + ulong recno; + TRUSTREC delrec; + int delrecidx; + int newflag = 0; + ulong newlid = 0; + PKT_public_key *pk = m_alloc_clear( sizeof *pk ); + ulong pk_lid = 0; + int found_sig = 0; + int found_delrec = 0; + int rc; + + 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; + + /* Loop over all signatures just in case one is not correctly + * marked. If we see the correct signature, set a flag. + * delete duplicate signatures (should not happen but...) */ + for( recno = urec->r.uid.siglist; recno; recno = rec.r.sig.next ) { + int i; + + read_record( recno, &rec, RECTYPE_SIG ); + for(i=0; i < SIGS_PER_RECORD; i++ ) { + TRUSTREC tmp; + if( !rec.r.sig.sig[i].lid ) { + if( !found_delrec && !delrec.recnum ) { + delrec = rec; + delrecidx = i; + found_delrec=1; + } + continue; /* skip deleted sigs */ + } + if( rec.r.sig.sig[i].lid == pk_lid ) { + if( found_sig ) { + log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " + "duplicated signature - deleted\n"), + (ulong)keyid[1], lid, uidhash[18], + uidhash[19], (ulong)sig->keyid[1] ); + rec.r.sig.sig[i].lid = 0; + rec.dirty = 1; + continue; + } + found_sig = 1; + } + if( rec.r.sig.sig[i].flag & SIGF_CHECKED ) + continue; /* we already checked this signature */ + if( rec.r.sig.sig[i].flag & SIGF_NOPUBKEY ) + continue; /* we do not have the public key */ + + read_record( rec.r.sig.sig[i].lid, &tmp, 0 ); + if( tmp.rectype == RECTYPE_DIR ) { + /* In this case we should now be able to check the signature */ + rc = check_key_signature( keyblock, signode, NULL ); + if( !rc ) { /* valid signature */ + if( opt.verbose ) + log_info(_( + "key %08lX.%lu, uid %02X%02X, sig %08lX: " + "Good signature (1)\n"), + (ulong)keyid[1], lid, uidhash[18], + uidhash[19], (ulong)sig->keyid[1] ); + rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID; + } + else if( rc == G10ERR_NO_PUBKEY ) { + log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " + "weird: no public key\n"), + (ulong)keyid[1], lid, uidhash[18], + uidhash[19], (ulong)sig->keyid[1] ); + rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; + } + else { + log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX:" + " %s\n"), + (ulong)keyid[1], lid, uidhash[18], + uidhash[19], (ulong)sig->keyid[1], + g10_errstr(rc)); + rec.r.sig.sig[i].flag = SIGF_CHECKED; + } + rec.dirty = 1; + } + else if( tmp.rectype == RECTYPE_SDIR ) { + /* must check that it is the right one */ + if( tmp.r.sdir.keyid[0] == sig->keyid[0] + && tmp.r.sdir.keyid[1] == sig->keyid[1] + && (!tmp.r.sdir.pubkey_algo + || tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) { + log_info(_("key %08lX.%lu, uid %02X%02X: " + "has shadow dir %lu but not yet marked.\n"), + (ulong)keyid[1], lid, + uidhash[18], uidhash[19], tmp.recnum ); + rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; + rec.dirty = 1; + /* fixme: should we verify that the record is + * in the hintlist? - This case here should anyway + * never occur */ + } + } + else { + log_error("sig record %lu[%d] points to wrong record.\n", + rec.r.sig.sig[i].lid, i ); + die_invalid_db(); + } + } + if( found_delrec && delrec.recnum ) { + delrec = rec; + found_delrec = 0; /* we only want the first one */ + } + if( rec.dirty ) { + write_record( &rec ); + rec.dirty = 0; + } + } + + if( found_sig ) + return; + + /* at this point, we have verified, that the signature is not in + * our list of signatures. Add a new record with that signature + * and if the public key is there, check the signature. */ + + if( !pk_lid ) /* we have already seen that there is no pubkey */ + rc = G10ERR_NO_PUBKEY; + else + rc = check_key_signature( keyblock, signode, NULL ); + + if( !rc ) { /* valid signature */ + if( opt.verbose ) + log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " + "Good signature (2)\n"), + (ulong)keyid[1], lid, uidhash[18], + uidhash[19], (ulong)sig->keyid[1] ); + newlid = pk_lid; /* this is the pk of the signature */ + newflag = SIGF_CHECKED | SIGF_VALID; + } + else if( rc == G10ERR_NO_PUBKEY ) { + if( opt.verbose > 1 ) + log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " + "no public key\n"), + (ulong)keyid[1], lid, uidhash[18], + uidhash[19], (ulong)sig->keyid[1] ); + newlid = create_shadow_dir( sig, lid ); + newflag = SIGF_NOPUBKEY; + } + else { + log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: %s\n"), + (ulong)keyid[1], lid, uidhash[18], uidhash[19], + (ulong)sig->keyid[1], g10_errstr(rc)); + newlid = create_shadow_dir( sig, lid ); + newflag = SIGF_CHECKED; + } + + if( delrec.recnum ) { /* we can reuse a deleted slot */ + delrec.r.sig.sig[delrecidx].lid = newlid; + delrec.r.sig.sig[delrecidx].flag= newflag; + write_record( &delrec ); + } + else { /* must insert a new sig record */ + TRUSTREC tmp; + + memset( &tmp, 0, sizeof tmp ); + tmp.recnum = tdbio_new_recnum(); + tmp.rectype = RECTYPE_SIG; + tmp.r.sig.lid = lid; + tmp.r.sig.next = urec->r.uid.siglist; + tmp.r.sig.sig[0].lid = newlid; + tmp.r.sig.sig[0].flag= newflag; + write_record( &tmp ); + urec->r.uid.siglist = tmp.recnum; + urec->dirty = 1; + } +} + + /**************** * Note: A signature made with a secondary key is not considered a @@ -2061,10 +2314,9 @@ upd_pref_record( PKT_signature *sig, TRUSTREC *drec, static void upd_sig_record( PKT_signature *sig, TRUSTREC *drec, u32 *keyid, ulong *uidrecno, byte *uidhash, - KBNODE keyblock, KBNODE signode ) + KBNODE keyblock, KBNODE signode) { TRUSTREC urec; - int rc; ulong lid = drec->recnum; if( !*uidrecno ) { @@ -2086,29 +2338,8 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec, if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) { if( (sig->sig_class&~3) == 0x10 ) { - /* must verify this selfsignature here, so that we can - * build the preference record and validate the uid record - */ - if( !(urec.r.uid.uidflags & UIDF_CHECKED) ) { - rc = check_key_signature( keyblock, signode, NULL ); - if( !rc ) { - if( opt.verbose ) - log_info(_( - "key %08lX.%lu, uid %02X%02X: " - "good self-signature\n"), - (ulong)keyid[1], lid, uidhash[18], - uidhash[19] ); - upd_pref_record( sig, drec, keyid, &urec, uidhash ); - urec.r.uid.uidflags = UIDF_CHECKED | UIDF_VALID; - } - else { - log_error("key %08lX, uid %02X%02X: " - "invalid self-signature: %s\n", (ulong)keyid[1], - uidhash[18], uidhash[19], g10_errstr(rc) ); - urec.r.uid.uidflags = UIDF_CHECKED; - } - urec.dirty = 1; - } + upd_self_key_sigs( sig, &urec, lid, keyid, uidhash, + keyblock, signode ); } else if( sig->sig_class == 0x18 ) { /* key binding */ /* get the corresponding key */ @@ -2126,264 +2357,8 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec, } } else if( (sig->sig_class&~3) == 0x10 ) { - /* We simply insert the signature into the sig records but - * avoid duplicate ones. We do not check them here because - * there is a big chance, that we import required public keys - * later. The problem with this is that we must somewhere store - * the information about this signature (we need a record id). - * We do this by using the record type shadow dir, which will - * be converted to a dir record as soon as a new public key is - * inserted into the trustdb. - */ - TRUSTREC rec; - ulong recno; - TRUSTREC delrec; - int delrecidx; - 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; - - delrec.recnum = 0; - - 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; - - /* Loop over all signatures just in case one is not correctly - * marked. If we see the correct signature, set a flag. - * delete duplicate signatures (should not happen but...) - */ - for( recno = urec.r.uid.siglist; recno; recno = rec.r.sig.next ) { - int i; - - read_record( recno, &rec, RECTYPE_SIG ); - for(i=0; i < SIGS_PER_RECORD; i++ ) { - TRUSTREC tmp; - if( !rec.r.sig.sig[i].lid ) { - if( !found_delrec && !delrec.recnum ) { - delrec = rec; - delrecidx = i; - found_delrec=1; - } - continue; /* skip deleted sigs */ - } - if( rec.r.sig.sig[i].lid == pk_lid ) { - if( found_sig ) { - log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "duplicated signature - deleted\n"), - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1] ); - rec.r.sig.sig[i].lid = 0; - rec.dirty = 1; - } - else - found_sig = 1; - } - if( rec.r.sig.sig[i].flag & SIGF_CHECKED ) - continue; /* we already checked this signature */ - if( rec.r.sig.sig[i].flag & SIGF_NOPUBKEY ) - continue; /* we do not have the public key */ - - read_record( rec.r.sig.sig[i].lid, &tmp, 0 ); - if( tmp.rectype == RECTYPE_DIR ) { - /* In this case we should now be able to check - * the signature: */ - rc = check_key_signature( keyblock, signode, NULL ); - if( !rc ) { /* valid signature */ - if( opt.verbose ) - log_info(_( - "key %08lX.%lu, uid %02X%02X, sig %08lX: " - "good signature (1)\n"), - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1] ); - rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID; - } - else if( rc == G10ERR_NO_PUBKEY ) { - log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "weird: no public key\n"), - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1] ); - rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; - } - else { - log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "invalid signature: %s\n"), - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1], - g10_errstr(rc)); - rec.r.sig.sig[i].flag = SIGF_CHECKED; - } - rec.dirty = 1; - } - else if( tmp.rectype == RECTYPE_SDIR ) { - /* must check that it is the right one */ - if( tmp.r.sdir.keyid[0] == sig->keyid[0] - && tmp.r.sdir.keyid[1] == sig->keyid[1] - && (!tmp.r.sdir.pubkey_algo - || tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) { - log_info(_("key %08lX.%lu, uid %02X%02X: " - "has shadow dir %lu but not yet marked.\n"), - (ulong)keyid[1], lid, - uidhash[18], uidhash[19], tmp.recnum ); - rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; - rec.dirty = 1; - /* fixme: should we verify that the record is - * in the hintlist? - This case here should anyway - * never occur */ - } - } - else { - log_error("sig record %lu[%d] points to wrong record.\n", - rec.r.sig.sig[i].lid, i ); - die_invalid_db(); - } - } - if( found_delrec && delrec.recnum ) { - delrec = rec; - found_delrec = 0; /* we onyl want the first one */ - } - if( rec.dirty ) - write_record( &rec ); - } - - if( found_sig ) - goto leave; - - /* at this point, we have verified, that the signature is not in - * our list of signatures. Add a new record with that signature - * and if the public key is there, check the signature. */ - - if( !pk_lid ) - rc = G10ERR_NO_PUBKEY; - else - rc = check_key_signature( keyblock, signode, NULL ); - - if( !rc ) { /* valid signature */ - if( opt.verbose ) - log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "good signature (2)\n"), - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1] ); - newlid = pk_lid; /* this is the pk of the signature */ - if( !newlid ) - BUG(); - newflag = SIGF_CHECKED | SIGF_VALID; - } - else if( rc == G10ERR_NO_PUBKEY ) { - if( opt.verbose > 1 ) - log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "no public key\n"), - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1] ); - newflag = SIGF_NOPUBKEY; - } - else { - log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " - "invalid signature: %s\n"), - (ulong)keyid[1], lid, uidhash[18], uidhash[19], - (ulong)sig->keyid[1], g10_errstr(rc)); - newflag = SIGF_CHECKED; - } - - if( !newlid ) { /* create a shadow dir record */ - TRUSTREC sdir, hlst, tmphlst; - int tmpidx; - /* first see whether we already have such a record */ - rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir ); - if( rc && rc != -1 ) { - log_error("tdbio_search_dir failed: %s\n", g10_errstr(rc)); - die_invalid_db(); - } - if( rc == -1 ) { /* not found: create */ - memset( &sdir, 0, sizeof sdir ); - sdir.recnum = tdbio_new_recnum(); - sdir.rectype= RECTYPE_SDIR; - sdir.r.sdir.lid = sdir.recnum; - sdir.r.sdir.keyid[0] = sig->keyid[0]; - sdir.r.sdir.keyid[1] = sig->keyid[1]; - sdir.r.sdir.pubkey_algo = sig->pubkey_algo; - sdir.r.sdir.hintlist = 0; - write_record( &sdir ); - } - newlid = sdir.recnum; - /* Put the record number into the hintlist. - * (It is easier to use the lid and not the record number of the - * key to save some space (assuming that a signator has - * signed more than one user id - and it is easier to implement.) - */ - tmphlst.recnum = 0; - for( recno=sdir.r.sdir.hintlist; recno; recno = hlst.r.hlst.next) { - int i; - read_record( recno, &hlst, RECTYPE_HLST ); - for( i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( !hlst.r.hlst.rnum[i] ) { - if( !tmphlst.recnum ) { - tmphlst = hlst; - tmpidx = i; - } - } - else if( hlst.r.hlst.rnum[i] == lid ) - goto have_hint; - } - } - /* not yet in the hint list, write it */ - if( tmphlst.recnum ) { /* we have an empty slot */ - tmphlst.r.hlst.rnum[tmpidx] = lid; - write_record( &tmphlst ); - } - else { /* must append a new hlst record */ - memset( &hlst, 0, sizeof hlst ); - hlst.recnum = tdbio_new_recnum(); - hlst.rectype = RECTYPE_HLST; - hlst.r.hlst.next = sdir.r.sdir.hintlist; - hlst.r.hlst.rnum[0] = lid; - write_record( &hlst ); - sdir.r.sdir.hintlist = hlst.recnum; - write_record( &sdir ); - } - have_hint: /* "goto considered useful" (don't tell Dijkstra) */ - ; - } - - if( delrec.recnum ) { /* we can reuse a deleted slot */ - delrec.r.sig.sig[delrecidx].lid = newlid; - delrec.r.sig.sig[delrecidx].flag= newflag; - write_record( &delrec ); - } - else { /* must insert a new sig record */ - TRUSTREC tmp; - - memset( &tmp, 0, sizeof tmp ); - tmp.recnum = tdbio_new_recnum(); - tmp.rectype = RECTYPE_SIG; - tmp.r.sig.lid = lid; - tmp.r.sig.next = urec.r.uid.siglist; - tmp.r.sig.sig[0].lid = newlid; - tmp.r.sig.sig[0].flag= newflag; - write_record( &tmp ); - urec.r.uid.siglist = tmp.recnum; - urec.dirty = 1; - } - + upd_nonself_key_sigs( sig, &urec, lid, keyid, uidhash, + keyblock, signode ); } else if( sig->sig_class == 0x18 ) { /* key binding */ log_info(_("key %08lX: bogus key binding by %08lX\n"), @@ -2398,12 +2373,13 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec, (ulong)keyid[1], (ulong)sig->keyid[1] ); } else if( sig->sig_class == 0x30 ) { /* cert revocation */ - /* FIXME: a signator wants to revoke his certification signature */ + /* fixme: a signator wants to revoke his certification signature */ } - leave: - if( urec.dirty ) + if( urec.dirty ) { write_record( &urec ); + urec.dirty = 0; + } } @@ -2415,7 +2391,7 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec, * key, the check is done by some special code in insert_trust_record(). */ int -update_trust_record( KBNODE keyblock ) +update_trust_record( KBNODE keyblock, int *modified ) { PKT_public_key *primary_pk; KBNODE node; @@ -2432,6 +2408,9 @@ update_trust_record( KBNODE keyblock ) RECNO_LIST recno_list = NULL; /* list of verified records */ /* fixme: replace recno_list by a lookup on node->recno */ + if( modified ) + *modified = 0; + node = find_kbnode( keyblock, PKT_PUBLIC_KEY ); primary_pk = node->pkt->pkt.public_key; rc = get_dir_record( primary_pk, &drec ); @@ -2442,7 +2421,10 @@ update_trust_record( KBNODE keyblock ) keyid_from_pk( primary_pk, keyid ); - /* fixme: start a transaction */ + rc = tdbio_begin_transaction(); + if( rc ) + return rc; + /* now update keys and user ids */ for( node=keyblock; node; node = node->next ) { switch( node->pkt->pkttype ) { @@ -2458,17 +2440,16 @@ update_trust_record( KBNODE keyblock ) drec.dirty = 0; } upd_uid_record( node->pkt->pkt.user_id, &drec, &recno_list, - keyid, &uidrecno, uidhash ); + keyid, &uidrecno, uidhash ); break; case PKT_SIGNATURE: - if( drec.dirty ) { /* upd_sig_recrod may read the drec */ - + if( drec.dirty ) { /* upd_sig_recory may read the drec */ write_record( &drec ); drec.dirty = 0; } - upd_sig_record( node->pkt->pkt.signature, &drec, - keyid, &uidrecno, uidhash, keyblock, node ); + upd_sig_record( node->pkt->pkt.signature, &drec, keyid, + &uidrecno, uidhash, keyblock, node ); break; default: @@ -2531,11 +2512,15 @@ update_trust_record( KBNODE keyblock ) if( rc ) - ; /* fixme: cancel transaction */ - else if( drec.dirty ) { - drec.r.dir.dirflags &= ~DIRF_CHECKED; /* reset flag */ - write_record( &drec ); - do_sync(); + rc = tdbio_cancel_transaction(); + else { + if( drec.dirty ) { + drec.r.dir.dirflags &= ~DIRF_CHECKED; /* reset flag */ + write_record( &drec ); + } + if( modified && tdbio_is_dirty() ) + *modified = 0; + rc = tdbio_end_transaction(); } rel_recno_list( &recno_list ); return rc; @@ -2638,7 +2623,7 @@ insert_trust_record( PKT_public_key *pk ) } /* and put all the other stuff into the keydb */ - rc = update_trust_record( keyblock ); + rc = update_trust_record( keyblock, NULL ); if( !rc ) process_hintlist( hintlist, dirrec.r.dir.lid ); diff --git a/g10/trustdb.h b/g10/trustdb.h index 8cdf50ec1..01d3dab55 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -60,7 +60,7 @@ ulong lid_from_keyblock( KBNODE keyblock ); int query_trust_record( PKT_public_key *pk ); int clear_trust_checked_flag( PKT_public_key *pk ); int insert_trust_record( PKT_public_key *pk ); -int update_trust_record( KBNODE keyblock ); +int update_trust_record( KBNODE keyblock, int *modified ); int update_ownertrust( ulong lid, unsigned new_trust ); /*-- pkclist.c --*/ |