From e309a875cb938dff76983d00552ebcc08a5e90c1 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 21 Oct 1998 17:34:36 +0000 Subject: [PATCH] Epxerimenta support for GDBM keyings. --- ChangeLog | 13 ++ NEWS | 15 ++ PROJECTS | 8 +- THANKS | 2 + TODO | 2 - VERSION | 2 +- acinclude.m4 | 85 +------ cipher/ChangeLog | 4 + cipher/Makefile.am | 2 +- cipher/pubkey.c | 10 + configure.in | 26 ++- doc/DETAILS | 22 ++ g10/ChangeLog | 24 ++ g10/Makefile.am | 4 +- g10/delkey.c | 2 +- g10/getkey.c | 400 +++++++++++++++++++------------- g10/kbnode.c | 1 + g10/keydb.h | 6 + g10/keygen.c | 10 +- g10/keylist.c | 103 +++++---- g10/mainproc.c | 8 +- g10/ringedit.c | 551 ++++++++++++++++++++++++++++++++------------- g10/sign.c | 9 +- g10/tdbio.c | 148 ++++++------ g10/tdbio.h | 33 +-- g10/trustdb.c | 7 +- include/ChangeLog | 4 + include/distfiles | 1 + include/host2net.h | 43 ++++ include/iobuf.h | 2 + scripts/autogen.sh | 12 +- tools/Makefile.am | 10 +- util/ChangeLog | 5 + util/Makefile.am | 2 +- util/iobuf.c | 27 ++- util/logger.c | 4 +- 36 files changed, 1049 insertions(+), 558 deletions(-) create mode 100644 include/host2net.h diff --git a/ChangeLog b/ChangeLog index 6a1ac49e2..1a25ff32e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Wed Oct 21 17:24:24 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in: Removed gettext kludge + * acinclude.m4: Add patched AM_WITH_NKS macro + +Tue Oct 20 19:03:36 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in: Kludge to make AM_GNU_GETTEXT work, + changed some macors to more modern versions. Also + changeg the all makefiles to remove duplicate ../intl. + * acinclude.m4: Removed the gettext stuff, as this + already comes with automake now. + Wed Oct 14 12:11:34 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (NAME_OF_DEV_RANDOM): New. diff --git a/NEWS b/NEWS index 549a86933..1e359d035 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,18 @@ + + * Fixed the gettext configure bug. + + * Kludge for RSA keys: keyid and length of a RSA key are + correctly reported, but you get an error if you try to use + this key (If you do not have the non-US version). + + * Experimental support for keyrings stored in a GDBM database. + This is *much* faster than a standard keyring. You will notice + that the import gets slower with time; the reason is that all + new keys are used to verify signatures of previous inserted + keys. Use "--keyring gnupg-gdbm:". This is + not (yet) supported for secret keys. + + Noteworthy changes in version 0.4.2 ----------------------------------- diff --git a/PROJECTS b/PROJECTS index 835bf2292..10afb9976 100644 --- a/PROJECTS +++ b/PROJECTS @@ -1,6 +1,10 @@ - - abstraction of the MPI + * abstraction of the MPI - - Add a way to override the current cipher/md implementations + * Add a way to override the current cipher/md implementations by others (using extensions) + * add a fast-import command which does not do the signature checks + of other keys (processing of the sdir hintlist). The signatures + may then be verified by a maintainence pass. + diff --git a/THANKS b/THANKS index baaf5f1fc..88e7c2311 100644 --- a/THANKS +++ b/THANKS @@ -17,6 +17,8 @@ Ed Boraas ecxjo@esperanto.org Ernst Molitor ernst.molitor@uni-bonn.de Frank Heckenbach heckenb@mi.uni-erlangen.de Gaël Quéri gqueri@mail.dotcom.fr +Greg Louis glouis@dynamicro.on.ca +Gregory Steuck steuck@iname.com Hendrik Buschkamp buschkamp@rheumanet.org Holger Schurig holger@d.om.org Hugh Daniel hugh@toad.com diff --git a/TODO b/TODO index 6cc2398f9..a17096a7e 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ - * There is a new memory leak in update-trustdb :-( - * Fix ;) revocation and expire stuff. * OpenBSD: dynamic loading with dlopen works on OpenBSD, but: diff --git a/VERSION b/VERSION index 2b7c5ae01..61f859e21 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.2 +0.4.2a diff --git a/acinclude.m4 b/acinclude.m4 index f540edc63..fbbe2d00d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -209,83 +209,12 @@ define(WK_CHECK_MLOCK, ]) -###################################################################### -# progtest.m4 from gettext 0.35 -###################################################################### -# Search path for a program which passes the given test. -# Ulrich Drepper , 1996. -# -# This file can be copied and used freely without restrictions. It can -# be used in projects which are not available under the GNU Public License -# but which still want to provide support for the GNU gettext functionality. -# Please note that the actual code is *not* freely available. -# serial 1 -dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, -dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) -AC_DEFUN(AM_PATH_PROG_WITH_TEST, -[# Extract the first word of "$2", so it can be a program name with args. -set dummy $2; ac_word=[$]2 -AC_MSG_CHECKING([for $ac_word]) -AC_CACHE_VAL(ac_cv_path_$1, -[case "[$]$1" in - /*) - ac_cv_path_$1="[$]$1" # Let the user override the test with a path. - ;; - *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in ifelse([$5], , $PATH, [$5]); do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - if [$3]; then - ac_cv_path_$1="$ac_dir/$ac_word" - break - fi - fi - done - IFS="$ac_save_ifs" -dnl If no 4th arg is given, leave the cache variable unset, -dnl so AC_PATH_PROGS will keep looking. -ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" -])dnl - ;; -esac])dnl -$1="$ac_cv_path_$1" -if test -n "[$]$1"; then - AC_MSG_RESULT([$]$1) -else - AC_MSG_RESULT(no) -fi -AC_SUBST($1)dnl -]) -###################################################################### -# lcmessage.m4 from gettext 0.35 -###################################################################### -# Check whether LC_MESSAGES is available in . -# Ulrich Drepper , 1995. -# -# This file can be copied and used freely without restrictions. It can -# be used in projects which are not available under the GNU Public License -# but which still want to provide support for the GNU gettext functionality. -# Please note that the actual code is *not* freely available. -# serial 1 -AC_DEFUN(AM_LC_MESSAGES, - [if test $ac_cv_header_locale_h = yes; then - AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, - [AC_TRY_LINK([#include ], [return LC_MESSAGES], - am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) - if test $am_cv_val_LC_MESSAGES = yes; then - AC_DEFINE(HAVE_LC_MESSAGES) - fi - fi]) -###################################################################### -# gettext.m4 from gettext 0.35 -###################################################################### # Macro to add for using GNU gettext. # Ulrich Drepper , 1995. # @@ -294,7 +223,7 @@ AC_DEFUN(AM_LC_MESSAGES, # but which still want to provide support for the GNU gettext functionality. # Please note that the actual code is *not* freely available. -# serial 5 +# serial 5 + patch (wk 21.10.98) AC_DEFUN(AM_WITH_NLS, [AC_MSG_CHECKING([whether NLS is requested]) @@ -334,14 +263,15 @@ AC_DEFUN(AM_WITH_NLS, if test "$gt_cv_func_gettext_libc" != "yes"; then AC_CHECK_LIB(intl, bindtextdomain, - [AC_CACHE_CHECK([for gettext in libintl], - gt_cv_func_gettext_libintl, - [AC_CHECK_LIB(intl, gettext, - gt_cv_func_gettext_libintl=yes, - gt_cv_func_gettext_libintl=no)], + [AC_CHECK_LIB(intl, gettext, + gt_cv_func_gettext_libintl=yes, gt_cv_func_gettext_libintl=no)]) fi + if test "$gt_cv_func_gettext_libintl" = "yes" ; then + LIBS="-lintl $LIBS" + fi + if test "$gt_cv_func_gettext_libc" = "yes" \ || test "$gt_cv_func_gettext_libintl" = "yes"; then AC_DEFINE(HAVE_GETTEXT) @@ -481,6 +411,7 @@ AC_DEFUN(AM_WITH_NLS, AC_SUBST(POSUB) ]) + AC_DEFUN(AM_GNU_GETTEXT, [AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AC_PROG_CC])dnl diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 99cd30128..58997ecab 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,7 @@ +Mon Oct 19 18:34:30 1998 me,,, (wk@tobold) + + * pubkey.c: Hack to allow us to give some info about RSA keys back. + Thu Oct 15 11:47:57 1998 Werner Koch (wk@isil.d.shuttle.de) * dynload.c: Support for DLD diff --git a/cipher/Makefile.am b/cipher/Makefile.am index e151de578..1b96cb0b5 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -2,7 +2,7 @@ gnupg_extensions = tiger twofish -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -I../intl +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl noinst_LIBRARIES = libcipher.a if ENABLE_GNUPG_EXTENSIONS diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 62a48a6d8..514711700 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -309,6 +309,8 @@ pubkey_get_npkey( int algo ) if( pubkey_table[i].algo == algo ) return pubkey_table[i].npkey; } while( load_pubkey_modules() ); + if( is_RSA(algo) ) /* special hack, so that we are able to */ + return 2; /* see the RSA keyids */ return 0; } @@ -324,6 +326,8 @@ pubkey_get_nskey( int algo ) if( pubkey_table[i].algo == algo ) return pubkey_table[i].nskey; } while( load_pubkey_modules() ); + if( is_RSA(algo) ) /* special hack, so that we are able to */ + return 6; /* see the RSA keyids */ return 0; } @@ -339,6 +343,8 @@ pubkey_get_nsig( int algo ) if( pubkey_table[i].algo == algo ) return pubkey_table[i].nsig; } while( load_pubkey_modules() ); + if( is_RSA(algo) ) /* special hack, so that we are able to */ + return 1; /* see the RSA keyids */ return 0; } @@ -354,6 +360,8 @@ pubkey_get_nenc( int algo ) if( pubkey_table[i].algo == algo ) return pubkey_table[i].nenc; } while( load_pubkey_modules() ); + if( is_RSA(algo) ) /* special hack, so that we are able to */ + return 1; /* see the RSA keyids */ return 0; } @@ -370,6 +378,8 @@ pubkey_nbits( int algo, MPI *pkey ) if( pubkey_table[i].algo == algo ) return (*pubkey_table[i].get_nbits)( algo, pkey ); } while( load_pubkey_modules() ); + if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */ + return mpi_get_nbits( pkey[0] ); return 0; } diff --git a/configure.in b/configure.in index 28cebf76a..93ef19d0a 100644 --- a/configure.in +++ b/configure.in @@ -3,6 +3,9 @@ dnl Configure template for GNUPG dnl dnl (Process this file with autoconf to produce a configure script.) +dnl Must reset CDPATH so that bash's cd does not print to stdout +CDPATH= + AC_INIT(g10/g10.c) AC_CONFIG_AUX_DIR(scripts) AM_CONFIG_HEADER(config.h) @@ -53,15 +56,12 @@ AC_ARG_WITH(included-zlib, [g10_force_zlib=yes], [g10_force_zlib=no] ) AC_MSG_RESULT($g10_force_zlib) - -AC_CANONICAL_SYSTEM -WK_CHECK_CACHE - dnl Checks for programs. -AC_PROG_MAKE_SET +AC_CANONICAL_SYSTEM AC_ARG_PROGRAM - +AC_PROG_MAKE_SET +AM_SANITY_CHECK missing_dir=`cd $ac_aux_dir && pwd` AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) @@ -87,6 +87,12 @@ case "${target}" in ac_cv_have_dev_random=no AC_DEFINE(USE_RAND_W32) ;; + *-*-hpux*) + if test -z "$GCC" ; then + CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE" + fi + AC_DEFINE(USE_RAND_UNIX) + ;; *) AC_DEFINE(USE_RAND_UNIX) ;; @@ -124,6 +130,8 @@ AC_DEFINE_UNQUOTED(NAME_OF_DEV_URANDOM, "$NAME_OF_DEV_URANDOM") dnl Checks for libraries. +AM_GNU_GETTEXT + AC_CHECK_LIB(gdbm,gdbm_firstkey) if test "$try_dynload" = yes ; then @@ -261,12 +269,8 @@ fi fi AC_SUBST(ZLIBS) - -WK_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl ) - WK_DO_LINK_FILES -AM_GNU_GETTEXT AC_OUTPUT([ Makefile @@ -280,7 +284,5 @@ doc/Makefile tools/Makefile zlib/Makefile checks/Makefile -],[echo timestamp >stamp-h; \ - sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile ]) diff --git a/doc/DETAILS b/doc/DETAILS index c40e86a52..0ac48bdc1 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -349,6 +349,28 @@ There is one enhancement used with the old style packet headers: + that this is the last packet. +Usage of gdbm files for keyrings +================================ + The key to store the keyblokc is it's fingerpint, other records + are used for secondary keys. fingerprints are always 20 bytes + where 16 bit fingerprints are appded with zero. + The first byte of the key gives some information on the type of the + key. + 1 = key is a 20 bit fingerprint (16 bytes fpr are padded with zeroes) + data is the keyblock + 2 = key is the complete 8 byte keyid + data is a list of 20 byte fingerprints + 3 = key is the short 4 byte keyid + data is a list of 20 byte fingerprints + 4 = key is the email address + data is a list of 20 byte fingerprints + + Data is prepended with a type byte: + 1 = keyblock + 2 = list of 20 byte padded fingerprints + 3 = list of list fingerprints (but how to we key them?) + + Other Notes diff --git a/g10/ChangeLog b/g10/ChangeLog index 72e0244e4..f16a600b6 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,27 @@ +Wed Oct 21 18:19:36 1998 Michael Roth + + * ringedit.c (add_keyblock_resource): Directory is now created. + * tdbio.c (tdbio_set_dbname): New info message. + +Wed Oct 21 11:52:04 1998 Werner Koch (wk@isil.d.shuttle.de) + + * trustdb.c (update_trustdb): released keyblock in loop. + + * keylist.c (list_block): New. + (list_all): Changed to use list_block. + + * trustdb.c: Completed support for GDBM + + * sign.c (only_old_style): Changed the way force_v3 is handled + (sign_file): Ditto. + (clearsign_file): Ditto. + + * keygen.c (has_invalid_email_chars): Splitted into mailbox and + host part. + + * keylist.c (list_one): Add a merge_keys_and_selfsig. + * mainproc.c (proc_tree): Ditto. + Sun Oct 18 11:49:03 1998 Werner Koch (wk@isil.d.shuttle.de) * sign.c (only_old_style): Add option force_v3_sigs diff --git a/g10/Makefile.am b/g10/Makefile.am index da04fece3..75838524a 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -I../intl +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl EXTRA_DIST = OPTIONS pubring.asc OMIT_DEPENDENCIES = zlib.h zconf.h LDFLAGS = @LDFLAGS@ @DYNLINK_LDFLAGS@ @@ -76,7 +76,7 @@ gpgm_SOURCES = dearmor.c \ # $(common_source) -LDADD = @INTLLIBS@ $(needed_libs) @ZLIBS@ +LDADD = $(needed_libs) @ZLIBS@ @INTLLIBS@ gpgm_LDADD = g10maint.o $(LDADD) diff --git a/g10/delkey.c b/g10/delkey.c index 210528404..b84a8bfd7 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -1,4 +1,4 @@ -/* delkey.c - delte keys +/* delkey.c - delete keys * Copyright (C) 1998 Free Software Foundation, Inc. * * This file is part of GNUPG. diff --git a/g10/getkey.c b/g10/getkey.c index 3aa12033d..1756a3556 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -683,6 +683,182 @@ merge_keys_and_selfsig( KBNODE keyblock ) } +static KBNODE +find_by_name( KBNODE keyblock, PKT_public_key *pk, const char *name, + int mode, byte *namehash, int *use_namehash ) +{ + KBNODE k, kk; + + for(k=keyblock; k; k = k->next ) { + if( k->pkt->pkttype == PKT_USER_ID + && !compare_name( k->pkt->pkt.user_id->name, + k->pkt->pkt.user_id->len, name, mode)) { + /* we found a matching name, look for the key */ + for(kk=keyblock; kk; kk = kk->next ) { + if( ( kk->pkt->pkttype == PKT_PUBLIC_KEY + || kk->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + && ( !pk->pubkey_algo + || pk->pubkey_algo + == kk->pkt->pkt.public_key->pubkey_algo) + && ( !pk->pubkey_usage + || !check_pubkey_algo2( + kk->pkt->pkt.public_key->pubkey_algo, + pk->pubkey_usage )) + ) + break; + } + if( kk ) { + u32 aki[2]; + keyid_from_pk( kk->pkt->pkt.public_key, aki ); + cache_user_id( k->pkt->pkt.user_id, aki ); + rmd160_hash_buffer( namehash, + k->pkt->pkt.user_id->name, + k->pkt->pkt.user_id->len ); + *use_namehash = 1; + return kk; + } + else if( is_RSA(pk->pubkey_algo) ) + log_error("RSA key cannot be used in this version\n"); + else + log_error("No key for userid\n"); + } + } + return NULL; +} + + +static KBNODE +find_by_keyid( KBNODE keyblock, PKT_public_key *pk, u32 *keyid, int mode ) +{ + KBNODE k; + + if( DBG_CACHE ) + log_debug("lookup keyid=%08lx%08lx req_algo=%d mode=%d\n", + (ulong)keyid[0], (ulong)keyid[1], pk->pubkey_algo, mode ); + + for(k=keyblock; k; k = k->next ) { + if( k->pkt->pkttype == PKT_PUBLIC_KEY + || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { + u32 aki[2]; + keyid_from_pk( k->pkt->pkt.public_key, aki ); + if( DBG_CACHE ) + log_debug(" aki=%08lx%08lx algo=%d\n", + (ulong)aki[0], (ulong)aki[1], + k->pkt->pkt.public_key->pubkey_algo ); + + if( aki[1] == keyid[1] + && ( mode == 10 || aki[0] == keyid[0] ) + && ( !pk->pubkey_algo + || pk->pubkey_algo + == k->pkt->pkt.public_key->pubkey_algo) ){ + KBNODE kk; + /* cache the userid */ + for(kk=keyblock; kk; kk = kk->next ) + if( kk->pkt->pkttype == PKT_USER_ID ) + break; + if( kk ) + cache_user_id( kk->pkt->pkt.user_id, aki ); + else + log_error("No userid for key\n"); + return k; /* found */ + } + } + } + return NULL; +} + + +static KBNODE +find_first( KBNODE keyblock, PKT_public_key *pk ) +{ + KBNODE k; + + for(k=keyblock; k; k = k->next ) { + if( k->pkt->pkttype == PKT_PUBLIC_KEY + || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + { + if( !pk->pubkey_algo + || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo ) + return k; + } + } + return NULL; +} + + +static KBNODE +find_by_fpr( KBNODE keyblock, PKT_public_key *pk, const char *name, int mode ) +{ + KBNODE k; + + for(k=keyblock; k; k = k->next ) { + if( k->pkt->pkttype == PKT_PUBLIC_KEY + || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { + byte afp[MAX_FINGERPRINT_LEN]; + size_t an; + + fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an ); + + if( DBG_CACHE ) { + u32 aki[2]; + keyid_from_pk( k->pkt->pkt.public_key, aki ); + log_debug(" aki=%08lx%08lx algo=%d mode=%d an=%u\n", + (ulong)aki[0], (ulong)aki[1], + k->pkt->pkt.public_key->pubkey_algo, mode, an ); + } + + if( an == mode + && !memcmp( afp, name, an) + && ( !pk->pubkey_algo + || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo) ) + return k; + } + } + return NULL; +} + + +static void +finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash, + int use_namehash, int primary ) +{ + assert( k->pkt->pkttype == PKT_PUBLIC_KEY + || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ); + assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ); + if( primary && !pk->pubkey_usage ) { + copy_public_key_new_namehash( pk, keyblock->pkt->pkt.public_key, + use_namehash? namehash:NULL); + merge_one_pk_and_selfsig( keyblock, keyblock ); + } + else { + if( primary && pk->pubkey_usage + && check_pubkey_algo2( k->pkt->pkt.public_key->pubkey_algo, + pk->pubkey_usage ) == G10ERR_WR_PUBKEY_ALGO ) { + /* if the usage is not correct, try to use a subkey */ + KBNODE save_k = k; + + for( ; k; k = k->next ) { + if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY + && !check_pubkey_algo2( + k->pkt->pkt.public_key->pubkey_algo, + pk->pubkey_usage ) ) + break; + } + if( !k ) + k = save_k; + else + log_info(_("using secondary key %08lX " + "instead of primary key %08lX\n"), + (ulong)keyid_from_pk( k->pkt->pkt.public_key, NULL), + (ulong)keyid_from_pk( save_k->pkt->pkt.public_key, NULL) + ); + } + + copy_public_key_new_namehash( pk, k->pkt->pkt.public_key, + use_namehash? namehash:NULL); + merge_one_pk_and_selfsig( keyblock, k ); + } +} @@ -709,175 +885,87 @@ lookup( PKT_public_key *pk, int mode, u32 *keyid, { int rc; KBNODE keyblock = NULL; + KBNODE k; KBPOS kbpos; int oldmode = set_packet_list_mode(0); byte namehash[20]; int use_namehash=0; - rc = enum_keyblocks( 0, &kbpos, &keyblock ); - if( rc ) { - if( rc == -1 ) - rc = G10ERR_NO_PUBKEY; - else if( rc ) - log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) ); - goto leave; + /* try the quick functions */ + k = NULL; + switch( mode ) { + case 10: + case 11: + rc = locate_keyblock_by_keyid( &kbpos, keyid, mode==10, 0 ); + if( !rc ) + rc = read_keyblock( &kbpos, &keyblock ); + if( !rc ) + k = find_by_keyid( keyblock, pk, keyid, mode ); + break; + + case 16: + case 20: + rc = locate_keyblock_by_fpr( &kbpos, name, mode, 0 ); + if( !rc ) + rc = read_keyblock( &kbpos, &keyblock ); + if( !rc ) + k = find_by_fpr( keyblock, pk, name, mode ); + break; + + default: rc = G10ERR_UNSUPPORTED; + } + if( !rc ) { + if( !k ) { + log_error("lookup: key has been located but was not found\n"); + rc = G10ERR_INV_KEYRING; + } + else + finish_lookup( keyblock, pk, k, namehash, 0, primary ); } - while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) { - KBNODE k, kk; - if( mode < 10 ) { /* name lookup */ - for(k=keyblock; k; k = k->next ) { - if( k->pkt->pkttype == PKT_USER_ID - && !compare_name( k->pkt->pkt.user_id->name, - k->pkt->pkt.user_id->len, name, mode)) { - /* we found a matching name, look for the key */ - for(kk=keyblock; kk; kk = kk->next ) { - if( ( kk->pkt->pkttype == PKT_PUBLIC_KEY - || kk->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - && ( !pk->pubkey_algo - || pk->pubkey_algo - == kk->pkt->pkt.public_key->pubkey_algo) - && ( !pk->pubkey_usage - || !check_pubkey_algo2( - kk->pkt->pkt.public_key->pubkey_algo, - pk->pubkey_usage )) - ) - break; - } - if( kk ) { - u32 aki[2]; - keyid_from_pk( kk->pkt->pkt.public_key, aki ); - cache_user_id( k->pkt->pkt.user_id, aki ); - rmd160_hash_buffer( namehash, - k->pkt->pkt.user_id->name, - k->pkt->pkt.user_id->len ); - use_namehash = 1; - k = kk; - break; - } - else - log_error("No key for userid\n"); + /* if this was not possible, loop over all keyblocks + * fixme: If one of the resources in the quick functions above + * works, but the key was not found, we will not find it + * in the other resources */ + if( rc == G10ERR_UNSUPPORTED ) { + rc = enum_keyblocks( 0, &kbpos, &keyblock ); + if( !rc ) { + while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) { + if( mode < 10 ) + k = find_by_name( keyblock, pk, name, mode, + namehash, &use_namehash); + else if( mode == 10 || mode == 11 ) + k = find_by_keyid( keyblock, pk, keyid, mode ); + else if( mode == 15 ) + k = find_first( keyblock, pk ); + else if( mode == 16 || mode == 20 ) + k = find_by_fpr( keyblock, pk, name, mode ); + else + BUG(); + if( k ) { + finish_lookup( keyblock, pk, k, namehash, + use_namehash, primary ); + break; /* found */ } - } - } - else { /* keyid or fingerprint lookup */ - if( DBG_CACHE && (mode== 10 || mode==11) ) { - log_debug("lookup keyid=%08lx%08lx req_algo=%d mode=%d\n", - (ulong)keyid[0], (ulong)keyid[1], - pk->pubkey_algo, mode ); - } - for(k=keyblock; k; k = k->next ) { - if( k->pkt->pkttype == PKT_PUBLIC_KEY - || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - if( mode == 10 || mode == 11 ) { - u32 aki[2]; - keyid_from_pk( k->pkt->pkt.public_key, aki ); - if( DBG_CACHE ) { - log_debug(" aki=%08lx%08lx algo=%d\n", - (ulong)aki[0], (ulong)aki[1], - k->pkt->pkt.public_key->pubkey_algo ); - } - if( aki[1] == keyid[1] - && ( mode == 10 || aki[0] == keyid[0] ) - && ( !pk->pubkey_algo - || pk->pubkey_algo - == k->pkt->pkt.public_key->pubkey_algo) ){ - /* cache the userid */ - for(kk=keyblock; kk; kk = kk->next ) - if( kk->pkt->pkttype == PKT_USER_ID ) - break; - if( kk ) - cache_user_id( kk->pkt->pkt.user_id, aki ); - else - log_error("No userid for key\n"); - break; /* found */ - } - } - else if( mode == 15 ) { /* get the first key */ - if( !pk->pubkey_algo - || pk->pubkey_algo - == k->pkt->pkt.public_key->pubkey_algo ) - break; - } - else if( mode == 16 || mode == 20 ) { - byte afp[MAX_FINGERPRINT_LEN]; - size_t an; - - fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an ); - - if( DBG_CACHE ) { - u32 aki[2]; - keyid_from_pk( k->pkt->pkt.public_key, aki ); - log_debug(" aki=%08lx%08lx algo=%d mode=%d an=%u\n", - (ulong)aki[0], (ulong)aki[1], - k->pkt->pkt.public_key->pubkey_algo, - mode, an ); - } - if( an == mode && !memcmp( afp, name, an) - && ( !pk->pubkey_algo - || pk->pubkey_algo - == k->pkt->pkt.public_key->pubkey_algo) ) { - break; - } - } - else - BUG(); - } /* end compare public keys */ - } - } - if( k ) { /* found */ - assert( k->pkt->pkttype == PKT_PUBLIC_KEY - || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ); - assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ); - if( primary && !pk->pubkey_usage ) { - copy_public_key_new_namehash( pk, keyblock->pkt->pkt.public_key, - use_namehash? namehash:NULL); - merge_one_pk_and_selfsig( keyblock, keyblock ); - } - else { - if( primary && pk->pubkey_usage - && check_pubkey_algo2( k->pkt->pkt.public_key->pubkey_algo, - pk->pubkey_usage ) == G10ERR_WR_PUBKEY_ALGO ) { - /* if the usage is not correct, try to use a subkey */ - KBNODE save_k = k; - - for( ; k; k = k->next ) { - if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY - && !check_pubkey_algo2( - k->pkt->pkt.public_key->pubkey_algo, - pk->pubkey_usage ) ) - break; - } - if( !k ) - k = save_k; - else - log_info(_("using secondary key %08lX " - "instead of primary key %08lX\n"), - (ulong)keyid_from_pk( k->pkt->pkt.public_key, NULL), - (ulong)keyid_from_pk( save_k->pkt->pkt.public_key, NULL) - ); - } - - copy_public_key_new_namehash( pk, k->pkt->pkt.public_key, - use_namehash? namehash:NULL); - merge_one_pk_and_selfsig( keyblock, k ); - } - if( ret_keyblock ) { - *ret_keyblock = keyblock; + release_kbnode( keyblock ); keyblock = NULL; } - break; /* enumeration */ } - release_kbnode( keyblock ); - keyblock = NULL; + enum_keyblocks( 2, &kbpos, &keyblock ); /* close */ + if( rc && rc != -1 ) + log_error("enum_keyblocks failed: %s\n", g10_errstr(rc)); } - if( rc == -1 ) - rc = G10ERR_NO_PUBKEY; - else if( rc ) - log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc)); - leave: - enum_keyblocks( 2, &kbpos, &keyblock ); /* close */ + if( !rc ) { + if( ret_keyblock ) { + *ret_keyblock = keyblock; + keyblock = NULL; + } + } + else if( rc == -1 ) + rc = G10ERR_NO_PUBKEY; + + release_kbnode( keyblock ); set_packet_list_mode(oldmode); if( opt.debug & DBG_MEMSTAT_VALUE ) { diff --git a/g10/kbnode.c b/g10/kbnode.c index 18b16d0bd..1048f316d 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -46,6 +46,7 @@ new_kbnode( PACKET *pkt ) n->pkt = pkt; n->flag = 0; n->private_flag=0; + n->recno = 0; return n; } diff --git a/g10/keydb.h b/g10/keydb.h index 229e525f6..f93d05a2c 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -46,6 +46,7 @@ struct kbnode_struct { PACKET *pkt; int flag; int private_flag; + ulong recno; /* used while updating the trustdb */ }; @@ -69,6 +70,7 @@ struct keyblock_pos_struct { int secret; /* working on a secret keyring */ #ifdef HAVE_LIBGDBM GDBM_FILE dbf; + byte keybuf[21]; #endif PACKET *pkt; /* ditto */ }; @@ -172,6 +174,10 @@ const char *enum_keyblock_resources( int *sequence, int secret ); int add_keyblock_resource( const char *resname, int force, int secret ); const char *keyblock_resource_name( KBPOS *kbpos ); int get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ); +int locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, + int fprlen, int secret ); +int locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, + int shortkid, int secret ); int find_keyblock( PUBKEY_FIND_INFO info, KBPOS *kbpos ); int find_keyblock_byname( KBPOS *kbpos, const char *username ); int find_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk ); diff --git a/g10/keygen.c b/g10/keygen.c index 1aac84fa4..6b04971ca 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -541,10 +541,18 @@ ask_expiredate() static int has_invalid_email_chars( const char *s ) { + int at_seen=0; + for( ; *s; s++ ) { if( *s & 0x80 ) return 1; - if( !strchr("01234567890abcdefghijklmnopqrstuvwxyz_-.@", *s ) ) + if( *s == '@' ) + at_seen=1; + else if( !at_seen + && !strchr("01234567890abcdefghijklmnopqrstuvwxyz_-.+", *s )) + return 1; + else if( at_seen + && !strchr("01234567890abcdefghijklmnopqrstuvwxyz_-.", *s ) ) return 1; } return 0; diff --git a/g10/keylist.c b/g10/keylist.c index 69e9b523b..a1150cdd5 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -37,6 +37,7 @@ static void list_all(int); static void list_one(const char *name, int secret); +static void list_keyblock( KBNODE keyblock, int secret ); static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk ); @@ -70,63 +71,87 @@ secret_key_list( int nnames, char **names ) static void list_all( int secret ) { - int i, seq=0; - const char *s; - IOBUF a; + KBPOS kbpos; + KBNODE keyblock = NULL; + int rc=0; + int lastresno; - /* FIXME: this assumes a keyring resource is a plain keyring file */ - while( (s = enum_keyblock_resources( &seq, secret )) ) { - if( !(a = iobuf_open(s)) ) { - log_error(_("can't open %s: %s\n"), s, strerror(errno)); - continue; - } - if( seq > 1 ) - putchar('\n'); - printf("%s\n", s ); - for(i=strlen(s); i; i-- ) - putchar('-'); - putchar('\n'); - - proc_packets( a ); - iobuf_close(a); + rc = enum_keyblocks( secret? 5:0, &kbpos, &keyblock ); + if( rc ) { + if( rc != -1 ) + log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) ); + goto leave; } + + lastresno = -1; + while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) { + if( lastresno != kbpos.resno ) { + const char *s = keyblock_resource_name( &kbpos ); + int i; + + lastresno = kbpos.resno; + printf("%s\n", s ); + for(i=strlen(s); i; i-- ) + putchar('-'); + putchar('\n'); + } + merge_keys_and_selfsig( keyblock ); + list_keyblock( keyblock, secret ); + release_kbnode( keyblock ); keyblock = NULL; + } + + if( rc && rc != -1 ) + log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc)); + + leave: + enum_keyblocks( 2, &kbpos, &keyblock ); /* close */ + release_kbnode( keyblock ); } + + static void list_one( const char *name, int secret ) { int rc = 0; KBNODE keyblock = NULL; + KBPOS kbpos; + + rc = secret? find_secret_keyblock_byname( &kbpos, name ) + : find_keyblock_byname( &kbpos, name ); + if( rc ) { + log_error("%s: user not found\n", name ); + return; + } + + rc = read_keyblock( &kbpos, &keyblock ); + if( rc ) { + log_error("%s: keyblock read problem: %s\n", name, g10_errstr(rc) ); + return; + } + merge_keys_and_selfsig( keyblock ); + list_keyblock( keyblock, secret ); + release_kbnode( keyblock ); +} + + +static void +list_keyblock( KBNODE keyblock, int secret ) +{ + int rc = 0; KBNODE kbctx; KBNODE node; - KBPOS kbpos; PKT_public_key *pk; PKT_secret_key *sk; u32 keyid[2]; int any=0; int trustletter = 0; - /* search the userid */ - rc = secret? find_secret_keyblock_byname( &kbpos, name ) - : find_keyblock_byname( &kbpos, name ); - if( rc ) { - log_error("%s: user not found\n", name ); - goto leave; - } - - /* read the keyblock */ - rc = read_keyblock( &kbpos, &keyblock ); - if( rc ) { - log_error("%s: keyblock read problem: %s\n", name, g10_errstr(rc) ); - goto leave; - } - - /* get the keyid from the keyblock */ node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY ); if( !node ) { log_error("Oops; key lost!\n"); - goto leave; + return; } if( secret ) { @@ -336,12 +361,10 @@ list_one( const char *name, int secret ) putchar(':'); putchar('\n'); } - - - leave: - release_kbnode( keyblock ); } + + static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk ) { diff --git a/g10/mainproc.c b/g10/mainproc.c index dd1546c6b..7980c22dc 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -886,10 +886,14 @@ proc_tree( CTX c, KBNODE node ) c->local_id = 0; c->trustletter = ' '; if( node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { + merge_keys_and_selfsig( node ); list_node( c, node ); - else if( node->pkt->pkttype == PKT_SECRET_KEY ) + } + else if( node->pkt->pkttype == PKT_SECRET_KEY ) { + merge_keys_and_selfsig( node ); list_node( c, node ); + } else if( node->pkt->pkttype == PKT_ONEPASS_SIG ) { /* check all signatures */ if( !c->have_data ) { diff --git a/g10/ringedit.c b/g10/ringedit.c index 119cd67d0..e414d0513 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -35,8 +35,6 @@ * * - Delete a key block * - * FIXME: Keep track of all nodes, so that a change is propagated - * to all nodes. (or use shallow copies and ref-counting?) */ @@ -59,10 +57,10 @@ #include "mpi.h" #include "iobuf.h" #include "keydb.h" +#include "host2net.h" #include "options.h" #include "i18n.h" -#undef HAVE_LIBGDBM /* <--- not ready */ struct resource_table_struct { int used; @@ -88,6 +86,14 @@ static int keyring_read( KBPOS *kbpos, KBNODE *ret_root ); static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ); static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root ); +#ifdef HAVE_LIBGDBM +static int do_gdbm_store( KBPOS *kbpos, KBNODE root, int update ); +static int do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, + const byte *fpr, int fprlen ); +static int do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid ); +static int do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ); +static int do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root ); +#endif static RESTBL * @@ -100,6 +106,14 @@ check_pos( KBPOS *kbpos ) return resource_table + kbpos->resno; } +#ifdef HAVE_LIBGDBM +static void +fatal_gdbm_error( const char *string ) +{ + log_fatal("gdbm failed: %s\n", string); +} + +#endif /* HAVE_LIBGDBM */ /**************************************************************** ****************** public functions **************************** @@ -188,9 +202,33 @@ add_keyblock_resource( const char *url, int force, int secret ) goto leave; } + /* see whether we can determine the filetype */ + if( rt == rt_UNKNOWN ) { + FILE *fp = fopen( filename, "rb" ); + + if( fp ) { + u32 magic; + + if( fread( &magic, 4, 1, fp) == 1 ) { + if( magic == 0x13579ace ) + rt = rt_GDBM; + else if( magic == 0xce9a5713 ) + log_error("%s: endianess does not match\n", url ); + else + rt = rt_RING; + } + fclose( fp ); + } + else /* no file yet: create ring */ + rt = rt_RING; + } switch( rt ) { case rt_UNKNOWN: + log_error("%s: unknown resource type\n", url ); + rc = G10ERR_GENERAL; + goto leave; + case rt_RING: iobuf = iobuf_fopen( filename, "rb" ); if( !iobuf && !force ) { @@ -199,20 +237,46 @@ add_keyblock_resource( const char *url, int force, int secret ) } if( !iobuf ) { + char *last_slash_in_filename; + + last_slash_in_filename = strrchr(filename, '/'); + *last_slash_in_filename = 0; + + if( access(filename, F_OK) ) { + if( strlen(filename) >= 7 + && !strcmp(filename+strlen(filename)-7, "/.gnupg") ) { + #if __MINGW32__ + if( mkdir(filename) ) + #else + if( mkdir(filename, S_IRUSR|S_IWUSR|S_IXUSR) ) + #endif + { + log_error( _("%s: can't create directory: %s\n"), + filename, strerror(errno)); + rc = G10ERR_OPEN_FILE; + goto leave; + } + else + log_info( _("%s: directory created\n"), filename ); + } + else + { + rc = G10ERR_OPEN_FILE; + goto leave; + } + } + + *last_slash_in_filename = '/'; + iobuf = iobuf_create( filename ); if( !iobuf ) { - log_error("%s: can't create: %s\n", filename, strerror(errno)); + log_error("%s: can't create keyring: %s\n", filename, strerror(errno)); rc = G10ERR_OPEN_FILE; goto leave; } else log_info("%s: keyring created\n", filename ); } - /* fixme: see whether it is really a ring or if type is unknown, - * try to figure out of what type it is - */ - rt = rt_RING; /* <--- FIXME */ - #ifdef __MINGW32__ /* must close it again */ iobuf_close( iobuf ); @@ -222,6 +286,17 @@ add_keyblock_resource( const char *url, int force, int secret ) #ifdef HAVE_LIBGDBM case rt_GDBM: + resource_table[i].dbf = gdbm_open( filename, 0, + force? GDBM_WRCREAT : GDBM_WRITER, + S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | S_IROTH, + fatal_gdbm_error ); + if( !resource_table[i].dbf ) { + log_error("%s: can't open gdbm file: %s\n", + filename, gdbm_strerror(gdbm_errno)); + rc = G10ERR_OPEN_FILE; + goto leave; + } break; #endif @@ -310,14 +385,21 @@ search( PACKET *pkt, KBPOS *kbpos, int secret ) resource_table[i].fname ); break; #ifdef HAVE_LIBGDBM - case rt_GDBM - rc = do_gdbm_search( pkt, kbpos, resource_table[i].dbf, - resource_table[i].fname ); + case rt_GDBM: { + PKT_public_key *req_pk = pkt->pkt.public_key; + byte fpr[20]; + size_t fprlen; + + fingerprint_from_pk( req_pk, fpr, &fprlen ); + rc = do_gdbm_locate( resource_table[i].dbf, + kbpos, fpr, fprlen ); + } break; #endif default: BUG(); } + kbpos->rt = resource_table[i].rt; if( !rc ) { kbpos->resno = i; kbpos->fp = NULL; @@ -404,6 +486,92 @@ find_secret_keyblock_byname( KBPOS *kbpos, const char *username ) } +/**************** + * Locate a keyblock in a database which is capable of direct access + * Put all information into KBPOS, which can be later be to access this + * key block. + * This function looks into all registered keyblock sources. + * + * Returns: 0 if found, + * -1 if not found + * G10ERR_UNSUPPORTED if no resource is able to handle this + * or another errorcode. + */ +int +locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret ) +{ + RESTBL *rentry; + int i, rc, any=0, last_rc=-1; + + + for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) { + if( rentry->used && !rentry->secret == !secret ) { + kbpos->rt = rentry->rt; + switch( rentry->rt ) { + case rt_GDBM: + any = 1; + rc = do_gdbm_locate( rentry->dbf, kbpos, fpr, fprlen ); + break; + default: + break; + } + + if( !rc ) { + kbpos->resno = i; + kbpos->fp = NULL; + return 0; + } + else if( rc != -1 ) { + log_error("error searching resource %d: %s\n", + i, g10_errstr(rc)); + last_rc = rc; + } + } + } + + return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc; +} + + +int +locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, int shortkid, int secret ) +{ + RESTBL *rentry; + int i, rc, any=0, last_rc=-1; + + if( shortkid ) + return G10ERR_UNSUPPORTED; + + for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) { + if( rentry->used && !rentry->secret == !secret ) { + kbpos->rt = rentry->rt; + switch( rentry->rt ) { + case rt_GDBM: + any = 1; + rc = do_gdbm_locate_by_keyid( rentry->dbf, kbpos, keyid ); + break; + default: + break; + } + + if( !rc ) { + kbpos->resno = i; + kbpos->fp = NULL; + return 0; + } + else if( rc != -1 ) { + log_error("error searching resource %d: %s\n", + i, g10_errstr(rc)); + last_rc = rc; + } + } + } + + return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc; +} + + + /**************** * Lock the keyblock; wait until it's available @@ -502,7 +670,8 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) break; #ifdef HAVE_LIBGDBM case rt_GDBM: - /* FIXME!!!! */ + /* FIXME: make sure that there is only one enum at a time */ + kbpos->offset = 0; break; #endif default: BUG(); @@ -521,7 +690,7 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) break; #ifdef HAVE_LIBGDBM case rt_GDBM: - /* FIXME!!!! */ + rc = do_gdbm_enum( kbpos, ret_root ); break; #endif default: BUG(); @@ -548,11 +717,8 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) kbpos->fp = NULL; } break; - #ifdef HAVE_LIBGDBM case rt_GDBM: - /* FIXME!!!! */ break; - #endif default: BUG(); } /* release pending packet */ @@ -583,7 +749,7 @@ insert_keyblock( KBPOS *kbpos, KBNODE root ) break; #ifdef HAVE_LIBGDBM case rt_GDBM: - /* FIXME!!!! */ + rc = do_gdbm_store( kbpos, root, 0 ); break; #endif default: BUG(); @@ -639,7 +805,7 @@ update_keyblock( KBPOS *kbpos, KBNODE root ) break; #ifdef HAVE_LIBGDBM case rt_GDBM: - /* FIXME!!!! */ + rc = do_gdbm_store( kbpos, root, 1 ); break; #endif default: BUG(); @@ -1129,58 +1295,179 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) ********** Functions which operates on GDM files *************** ****************************************************************/ +#if MAX_FINGERPRINT_LEN > 20 + #error A GDBM keyring assumes that fingerprints are less than 21 +#endif + +/**************** + * Insert the keyblock into the GDBM database + */ + +static int +do_gdbm_store( KBPOS *kbpos, KBNODE root, int update ) +{ + RESTBL *rentry; + PKT_public_key *pk; + KBNODE kbctx, node; + IOBUF fp = NULL; + byte fpr[20]; + byte contbuf[21]; + byte keybuf[21]; + size_t fprlen; + datum key, content; + int i, rc; + + if( !(rentry = check_pos( kbpos )) ) + return G10ERR_GENERAL; + + /* construct the fingerprint which is used as the primary key */ + node = find_kbnode( root, PKT_PUBLIC_KEY ); + if( !node ) + log_bug("a gdbm database can't store secret keys\n"); + pk = node->pkt->pkt.public_key; + + fingerprint_from_pk( pk, fpr, &fprlen ); + for(i=fprlen; i < DIM(fpr); i++ ) + fpr[i] = 0; + + /* build the keyblock */ + kbctx=NULL; + fp = iobuf_temp(); + iobuf_put( fp, 1 ); /* data is a keyblock */ + while( (node = walk_kbnode( root, &kbctx, 0 )) ) { + if( (rc = build_packet( fp, node->pkt )) ) { + log_error("build_packet(%d) failed: %s\n", + node->pkt->pkttype, g10_errstr(rc) ); + rc = G10ERR_WRITE_FILE; + goto leave; + } + } + /* store data and key */ + *keybuf = 1; /* key is a padded fingerprint */ + memcpy(keybuf+1, fpr, 20 ); + key.dptr = keybuf; + key.dsize = 21; + content.dptr = iobuf_get_temp_buffer( fp ); + content.dsize = iobuf_get_temp_length( fp ); + rc = gdbm_store( rentry->dbf, key, content, + update? GDBM_REPLACE : GDBM_INSERT ); + if( rc ) { + log_error("%s: gdbm_store failed: %s\n", rentry->fname, + rc == 1 ? "already stored" + : gdbm_strerror(gdbm_errno) ); + rc = G10ERR_WRITE_FILE; + goto leave; + } + /* now store all keyids */ + *contbuf = 2; /* data is a list of fingerprints */ + memcpy(contbuf+1, fpr, 20 ); + content.dptr = contbuf; + content.dsize= 21; + kbctx=NULL; + while( (node = walk_kbnode( root, &kbctx, 0 )) ) { + if( node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { + u32 aki[2]; + + keyid_from_pk( node->pkt->pkt.public_key, aki ); + *keybuf = 2; /* key is a 8 byte keyid */ + u32tobuf( keybuf+1 , aki[0] ); + u32tobuf( keybuf+5, aki[1] ); + key.dptr = keybuf; + key.dsize= 9; + /* fixme: must be more clever when a insert failed: + * build a list of fingerprints in this case */ + rc = gdbm_store( rentry->dbf, key, content, + update? GDBM_REPLACE : GDBM_INSERT ); + if( rc ) { + log_info("%s: gdbm_store keyid failed: %s\n", rentry->fname, + rc == 1 ? "already stored" + : gdbm_strerror(gdbm_errno) ); + rc = 0; + } + } + } + + leave: + iobuf_close(fp); /* don't need a cancel because it is a temp iobuf */ + return rc; +} + + + /**************** * search one keybox, return 0 if found, -1 if not found or an errorcode. */ static int -do_gdbm_search( PACKET *req, KBPOS *kbpos, GDBM_FILE dbf, const char *fname ) +do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, const byte *fpr, int fprlen ) { + byte *keybuf = kbpos->keybuf; + datum key; + int i; + + *keybuf = 1; + for(i=0; i < fprlen; i++ ) + keybuf[i+1] = fpr[i]; + for(; i < 20; i++ ) + keybuf[i+1] = 0; + + /* fetch the data */ + key.dptr = keybuf; + key.dsize = 21; + if( !gdbm_exists( dbf, key ) ) + return -1; /* not found */ + return 0; +} + +/**************** + * locate by keyid. + * FIXME: we must have a way to enumerate thru the list opf fingerprints + */ +static int +do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid ) +{ + byte keybuf[9]; + datum key, content; int rc; - PACKET pkt; - int save_mode; - ulong offset; - int pkttype = req->pkttype; - PKT_public_key *req_pk = req->pkt.public_key; - PKT_secret_key *req_sk = req->pkt.secret_key; - init_packet(&pkt); - save_mode = set_packet_list_mode(0); + /* construct the fingerprint which is used as the primary key */ + *keybuf = 2; + u32tobuf( keybuf+1, keyid[0] ); + u32tobuf( keybuf+5, keyid[1] ); + /* fetch the data */ + key.dptr = keybuf; + key.dsize = 9; + content = gdbm_fetch( dbf, key ); + if( !content.dptr ) + return -1; - while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) { - if( pkt.pkttype == PKT_SECRET_KEY ) { - PKT_secret_key *sk = pkt.pkt.secret_key; - - if( req_sk->timestamp == sk->timestamp - && req_sk->pubkey_algo == sk->pubkey_algo - && !cmp_seckey( req_sk, sk) ) - break; /* found */ - } - else if( pkt.pkttype == PKT_PUBLIC_KEY ) { - PKT_public_key *pk = pkt.pkt.public_key; - - if( req_pk->timestamp == pk->timestamp - && req_pk->pubkey_algo == pk->pubkey_algo - && !cmp_pubkey( req_pk, pk ) ) - break; /* found */ - } - else - BUG(); - free_packet(&pkt); + if( content.dsize < 2 ) { + log_error("gdbm_fetch did not return enough data\n" ); + free( content.dptr ); /* can't use m_free() here */ + return G10ERR_INV_KEYRING; } - if( !rc ) - kbpos->offset = offset; + if( *content.dptr != 2 ) { + log_error("gdbm_fetch returned unexpected type %d\n", + *(byte*)content.dptr ); + free( content.dptr ); /* can't use m_free() here */ + return G10ERR_INV_KEYRING; + } + if( content.dsize < 21 ) { + log_error("gdbm_fetch did not return a complete fingerprint\n" ); + free( content.dptr ); /* can't use m_free() here */ + return G10ERR_INV_KEYRING; + } + if( content.dsize > 21 ) + log_info("gdbm_fetch: warning: more than one fingerprint\n" ); - leave: - free_packet(&pkt); - set_packet_list_mode(save_mode); - #if __MINGW32__ - iobuf_close(iobuf); - #endif + rc = do_gdbm_locate( dbf, kbpos, content.dptr+1, 20 ); + free( content.dptr ); /* can't use m_free() here */ return rc; } + static int do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ) { @@ -1189,22 +1476,32 @@ do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ) RESTBL *rentry; KBNODE root = NULL; IOBUF a; - int in_cert = 0; + datum key, content; if( !(rentry=check_pos(kbpos)) ) return G10ERR_GENERAL; - a = iobuf_fopen( rentry->fname, "rb" ); - if( !a ) { - log_error("can't open '%s'\n", rentry->fname ); - return G10ERR_OPEN_FILE; + key.dptr = kbpos->keybuf; + key.dsize = 21; + content = gdbm_fetch( rentry->dbf, key ); + if( !content.dptr ) { + log_error("gdbm_fetch failed: %s\n", gdbm_strerror(gdbm_errno) ); + return G10ERR_INV_KEYRING; + } + if( content.dsize < 2 ) { + log_error("gdbm_fetch did not return enough data\n" ); + free( content.dptr ); /* can't use m_free() here */ + return G10ERR_INV_KEYRING; + } + if( *content.dptr != 1 ) { + log_error("gdbm_fetch returned unexpected type %d\n", + *(byte*)content.dptr ); + free( content.dptr ); /* can't use m_free() here */ + return G10ERR_INV_KEYRING; } - if( iobuf_seek( a, kbpos->offset ) ) { - log_error("can't seek to %lu\n", kbpos->offset); - iobuf_close(a); - return G10ERR_KEYRING_OPEN; - } + a = iobuf_temp_with_content( content.dptr+1, content.dsize-1 ); + free( content.dptr ); /* can't use m_free() here */ pkt = m_alloc( sizeof *pkt ); init_packet(pkt); @@ -1214,7 +1511,7 @@ do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ) if( rc != G10ERR_UNKNOWN_PACKET ) { log_error("read_keyblock: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; - goto ready; + break; } kbpos->count++; free_packet( pkt ); @@ -1222,27 +1519,16 @@ do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ) continue; } /* make a linked list of all packets */ - switch( pkt->pkttype ) { - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - if( in_cert ) - goto ready; - in_cert = 1; - default: - kbpos->count++; - if( !root ) - root = new_kbnode( pkt ); - else - add_kbnode( root, new_kbnode( pkt ) ); - pkt = m_alloc( sizeof *pkt ); - init_packet(pkt); - break; - } + kbpos->count++; + if( !root ) + root = new_kbnode( pkt ); + else + add_kbnode( root, new_kbnode( pkt ) ); + pkt = m_alloc( sizeof *pkt ); + init_packet(pkt); } - ready: if( rc == -1 && root ) rc = 0; - if( rc ) release_kbnode( root ); else @@ -1254,84 +1540,43 @@ do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ) } +/**************** + * Enum over keyblok data + */ static int -do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) +do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root ) { - PACKET *pkt; - int rc; RESTBL *rentry; - KBNODE root = NULL; + datum key, helpkey; if( !(rentry=check_pos(kbpos)) ) return G10ERR_GENERAL; - if( kbpos->pkt ) { - root = new_kbnode( kbpos->pkt ); - kbpos->pkt = NULL; + if( !kbpos->offset ) { + kbpos->offset = 1; + key = gdbm_firstkey( rentry->dbf ); } - - pkt = m_alloc( sizeof *pkt ); - init_packet(pkt); - while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) { - if( rc ) { /* ignore errors */ - if( rc != G10ERR_UNKNOWN_PACKET ) { - log_error("read_keyblock: read error: %s\n", g10_errstr(rc) ); - rc = G10ERR_INV_KEYRING; - goto ready; - } - free_packet( pkt ); - init_packet( pkt ); - continue; - } - /* make a linked list of all packets */ - switch( pkt->pkttype ) { - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - if( root ) { /* store this packet */ - kbpos->pkt = pkt; - pkt = NULL; - goto ready; - } - root = new_kbnode( pkt ); - pkt = m_alloc( sizeof *pkt ); - init_packet(pkt); - break; - - default: - /* skip pakets at the beginning of a keyring, until we find - * a start packet; issue a warning if it is not a comment */ - if( !root && pkt->pkttype != PKT_COMMENT - && pkt->pkttype != PKT_OLD_COMMENT ) { - log_info("keyring_enum: skipped packet of type %d\n", - pkt->pkttype ); - break; - } - if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE - ||pkt->pkttype == PKT_COMMENT - ||pkt->pkttype == PKT_OLD_COMMENT )) ) { - init_packet(pkt); - break; - } - add_kbnode( root, new_kbnode( pkt ) ); - pkt = m_alloc( sizeof *pkt ); - init_packet(pkt); - break; - } + else { + helpkey.dptr = kbpos->keybuf; + helpkey.dsize= 21; + key = gdbm_nextkey( rentry->dbf, helpkey ); } - ready: - if( rc == -1 && root ) - rc = 0; + while( key.dptr && (!key.dsize || *key.dptr != 1) ) { + helpkey = key; + key = gdbm_nextkey( rentry->dbf, helpkey ); + free( helpkey.dptr ); /* free and not m_free() ! */ + } + if( !key.dptr ) + return -1; /* eof */ - if( rc ) - release_kbnode( root ); - else - *ret_root = root; - free_packet( pkt ); - m_free( pkt ); - - return rc; + if( key.dsize < 21 ) { + free( key.dptr ); /* free and not m_free() ! */ + log_error("do_gdm_enum: key is too short\n" ); + return G10ERR_INV_KEYRING; + } + memcpy( kbpos->keybuf, key.dptr, 21 ); + free( key.dptr ); /* free and not m_free() ! */ + return do_gdbm_read( kbpos, ret_root ); } #endif /*HAVE_LIBGDBM*/ - - diff --git a/g10/sign.c b/g10/sign.c index 7404cac5d..1f4e1ce65 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -108,9 +108,6 @@ only_old_style( SK_LIST sk_list ) SK_LIST sk_rover = NULL; int old_style = 0; - if( opt.force_v3_sigs ) - return 1; - /* if there are only old style capable key we use the old sytle */ for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { PKT_secret_key *sk = sk_rover->sk; @@ -159,7 +156,6 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, int compr_algo = -1; /* unknown */ - memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); memset( &mfx, 0, sizeof mfx); @@ -181,6 +177,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, goto leave; if( !old_style ) old_style = only_old_style( sk_list ); + if( encrypt ) { if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC )) ) goto leave; @@ -372,7 +369,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, /* build the signature packet */ /* fixme: this code is partly duplicated in make_keysig_packet */ sig = m_alloc_clear( sizeof *sig ); - sig->version = old_style? 3 : sk->version; + sig->version = old_style || opt.force_v3_sigs ? 3 : sk->version; keyid_from_sk( sk, sig->keyid ); sig->digest_algo = hash_for(sk->pubkey_algo); sig->pubkey_algo = sk->pubkey_algo; @@ -608,7 +605,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) /* build the signature packet */ /* fixme: this code is duplicated above */ sig = m_alloc_clear( sizeof *sig ); - sig->version = old_style? 3 : sk->version; + sig->version = old_style || opt.force_v3_sigs ? 3 : sk->version; keyid_from_sk( sk, sig->keyid ); sig->digest_algo = hash_for(sk->pubkey_algo); sig->pubkey_algo = sk->pubkey_algo; diff --git a/g10/tdbio.c b/g10/tdbio.c index 5c1b7f427..76e606e0e 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -269,7 +269,7 @@ tdbio_set_dbname( const char *new_dbname, int create ) if( access( fname, R_OK ) ) { if( errno != ENOENT ) { - log_error_f( fname, _("can't access: %s\n"), strerror(errno) ); + log_error( _("%s: can't access: %s\n"), fname, strerror(errno) ); m_free(fname); return G10ERR_TRUSTDB; } @@ -289,17 +289,19 @@ tdbio_set_dbname( const char *new_dbname, int create ) #else if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) ) #endif - log_fatal_f( fname, _("can't create directory: %s\n"), - strerror(errno) ); + log_fatal( _("%s: can't create directory: %s\n"), + fname, strerror(errno) ); + else + log_info( _("%s: directory created\n"), fname ); } else - log_fatal_f(fname, _("directory does not exist!\n") ); + log_fatal( _("%s: directory does not exist!\n"), fname ); } *p = '/'; fp =fopen( fname, "wb" ); if( !fp ) - log_fatal_f( fname, _("can't create: %s\n"), strerror(errno) ); + log_fatal( _("%s: can't create: %s\n"), fname, strerror(errno) ); fclose(fp); m_free(db_name); db_name = fname; @@ -309,7 +311,7 @@ tdbio_set_dbname( const char *new_dbname, int create ) db_fd = open( db_name, O_RDWR ); #endif if( db_fd == -1 ) - log_fatal_f( db_name, _("can't open: %s\n"), strerror(errno) ); + log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) ); memset( &rec, 0, sizeof rec ); rec.r.ver.version = 2; @@ -320,11 +322,14 @@ tdbio_set_dbname( const char *new_dbname, int create ) if( !rc ) tdbio_sync(); if( rc ) - log_fatal_f( fname, _("failed to create version record: %s"), - g10_errstr(rc)); + log_fatal( _("%s: failed to create version record: %s"), + fname, g10_errstr(rc)); /* and read again to check that we are okay */ if( tdbio_read_record( 0, &rec, RECTYPE_VER ) ) - log_fatal_f( db_name, "invalid trust-db created\n" ); + log_fatal( _("%s: invalid trust-db created\n"), db_name ); + + log_info(_("%s: trust-db created\n"), db_name); + return 0; } } @@ -354,9 +359,9 @@ open_db() db_fd = open( db_name, O_RDWR ); #endif if( db_fd == -1 ) - log_fatal_f( db_name, _("can't open: %s\n"), strerror(errno) ); + log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) ); if( tdbio_read_record( 0, &rec, RECTYPE_VER ) ) - log_fatal_f( db_name, _("invalid trust-db\n") ); + log_fatal( _("%s: invalid trust-db\n"), db_name ); /* fixme: check ->locked and other stuff */ } @@ -390,16 +395,16 @@ create_hashtable( TRUSTREC *vr, int type ) rec.recnum = recnum; rc = tdbio_write_record( &rec ); if( rc ) - log_fatal_f(db_name,_("failed to create hashtable: %s\n"), - g10_errstr(rc)); + log_fatal( _("%s: failed to create hashtable: %s\n"), + db_name, g10_errstr(rc)); } /* update the version record */ rc = tdbio_write_record( vr ); if( !rc ) rc = tdbio_sync(); if( rc ) - log_fatal_f( db_name, _("error updating version record: %s\n"), - g10_errstr(rc)); + log_fatal( _("%s: error updating version record: %s\n"), + db_name, g10_errstr(rc)); } @@ -418,8 +423,8 @@ get_keyhashrec() rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); if( rc ) - log_fatal_f( db_name, _("error reading version record: %s\n"), - g10_errstr(rc) ); + log_fatal( _("%s: error reading version record: %s\n"), + db_name, g10_errstr(rc) ); if( !vr.r.ver.keyhashtbl ) create_hashtable( &vr, 0 ); @@ -443,8 +448,8 @@ get_sdirhashrec() rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); if( rc ) - log_fatal_f( db_name, _("error reading version record: %s\n"), - g10_errstr(rc) ); + log_fatal( _("%s: error reading version record: %s\n"), + db_name, g10_errstr(rc) ); if( !vr.r.ver.sdirhashtbl ) create_hashtable( &vr, 1 ); @@ -744,14 +749,14 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp ) rec->r.dir.uidlist, rec->r.dir.cacherec, rec->r.dir.ownertrust ); - if( rec->r.dir.dirflags & DIRF_ERROR ) - fputs(", error", fp ); - if( rec->r.dir.dirflags & DIRF_CHECKED ) - fputs(", checked", fp ); - if( rec->r.dir.dirflags & DIRF_REVOKED ) - fputs(", revoked", fp ); - if( rec->r.dir.dirflags & DIRF_MISKEY ) - fputs(", miskey", fp ); + if( rec->r.dir.dirflags & DIRF_CHECKED ) { + if( rec->r.dir.dirflags & DIRF_VALID ) + fputs(", valid", fp ); + if( rec->r.dir.dirflags & DIRF_EXPIRED ) + fputs(", expired", fp ); + if( rec->r.dir.dirflags & DIRF_REVOKED ) + fputs(", revoked", fp ); + } putc('\n', fp); break; case RECTYPE_KEY: @@ -761,8 +766,14 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp ) rec->r.key.pubkey_algo ); for(i=0; i < rec->r.key.fingerprint_len; i++ ) fprintf(fp, "%02X", rec->r.key.fingerprint[i] ); - if( rec->r.key.keyflags & KEYF_REVOKED ) - fputs(", revoked", fp ); + if( rec->r.key.keyflags & KEYF_CHECKED ) { + if( rec->r.key.keyflags & KEYF_VALID ) + fputs(", valid", fp ); + if( rec->r.key.keyflags & KEYF_EXPIRED ) + fputs(", expired", fp ); + if( rec->r.key.keyflags & KEYF_REVOKED ) + fputs(", revoked", fp ); + } putc('\n', fp); break; case RECTYPE_UID: @@ -772,12 +783,12 @@ 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_CHECKED ) - fputs(", checked", fp ); - if( rec->r.uid.uidflags & UIDF_VALID ) - fputs(", valid", fp ); - if( rec->r.uid.uidflags & UIDF_REVOKED ) - fputs(", revoked", fp ); + if( rec->r.uid.uidflags & UIDF_CHECKED ) { + if( rec->r.uid.uidflags & UIDF_VALID ) + fputs(", valid", fp ); + if( rec->r.uid.uidflags & UIDF_REVOKED ) + fputs(", revoked", fp ); + } putc('\n', fp); break; case RECTYPE_PREF: @@ -795,9 +806,19 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp ) fprintf(fp, "sig %lu, next=%lu,", rec->r.sig.lid, rec->r.sig.next ); for(i=0; i < SIGS_PER_RECORD; i++ ) { - if( rec->r.sig.sig[i].lid ) - fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid, - rec->r.sig.sig[i].flag ); + if( rec->r.sig.sig[i].lid ) { + fprintf(fp, " %lu:", rec->r.sig.sig[i].lid ); + if( rec->r.sig.sig[i].flag & SIGF_CHECKED ) { + fprintf(fp,"%c%c%c", + (rec->r.sig.sig[i].flag & SIGF_VALID) ? 'V':'-', + (rec->r.sig.sig[i].flag & SIGF_EXPIRED) ? 'E':'-', + (rec->r.sig.sig[i].flag & SIGF_REVOKED) ? 'R':'-'); + } + else if( rec->r.sig.sig[i].flag & SIGF_NOPUBKEY) + fputs("?--", fp); + else + fputs("---", fp); + } } putc('\n', fp); break; @@ -876,7 +897,7 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) break; case RECTYPE_VER: /* version record */ if( memcmp(buf+1, "gpg", 3 ) ) { - log_error_f( db_name, _("not a trustdb file\n") ); + log_error( _("%s: not a trustdb file\n"), db_name ); rc = G10ERR_TRUSTDB; } p += 2; /* skip "pgp" */ @@ -890,12 +911,12 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) rec->r.ver.firstfree =buftoulong(p); p += 4; rec->r.ver.sdirhashtbl =buftoulong(p); p += 4; if( recnum ) { - log_error_f( db_name, "version record with recnum %lu\n", + log_error( _("%s: version record with recnum %lu\n"), db_name, (ulong)recnum ); rc = G10ERR_TRUSTDB; } else if( rec->r.ver.version != 2 ) { - log_error_f( db_name, "invalid file version %d\n", + log_error( _("%s: invalid file version %d\n"), db_name, rec->r.ver.version ); rc = G10ERR_TRUSTDB; } @@ -911,8 +932,8 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) rec->r.dir.ownertrust = *p++; rec->r.dir.dirflags = *p++; if( rec->r.dir.lid != recnum ) { - log_error_f( db_name, "dir LID != recnum (%lu,%lu)\n", - rec->r.dir.lid, (ulong)recnum ); + log_error( "%s: dir LID != recnum (%lu,%lu)\n", + db_name, rec->r.dir.lid, (ulong)recnum ); rc = G10ERR_TRUSTDB; } break; @@ -957,8 +978,8 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) p += 3; rec->r.sdir.hintlist = buftoulong(p); if( rec->r.sdir.lid != recnum ) { - log_error_f( db_name, "sdir LID != recnum (%lu,%lu)\n", - rec->r.sdir.lid, (ulong)recnum ); + log_error( "%s: sdir LID != recnum (%lu,%lu)\n", + db_name, rec->r.sdir.lid, (ulong)recnum ); rc = G10ERR_TRUSTDB; } break; @@ -979,8 +1000,8 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) } break; default: - log_error_f( db_name, "invalid record type %d at recnum %lu\n", - rec->rectype, (ulong)recnum ); + log_error( "%s: invalid record type %d at recnum %lu\n", + db_name, rec->rectype, (ulong)recnum ); rc = G10ERR_TRUSTDB; break; } @@ -1122,8 +1143,8 @@ tdbio_delete_record( ulong recnum ) rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); if( rc ) - log_fatal_f( db_name, _("error reading version record: %s\n"), - g10_errstr(rc) ); + log_fatal( _("%s: error reading version record: %s\n"), + db_name, g10_errstr(rc) ); rec.recnum = recnum; rec.rectype = RECTYPE_FREE; @@ -1149,22 +1170,22 @@ tdbio_new_recnum() /* look for unused records */ rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); if( rc ) - log_fatal_f( db_name, _("error reading version record: %s\n"), - g10_errstr(rc) ); + log_fatal( _("%s: error reading version record: %s\n"), + db_name, g10_errstr(rc) ); if( vr.r.ver.firstfree ) { recnum = vr.r.ver.firstfree; rc = tdbio_read_record( recnum, &rec, RECTYPE_FREE ); if( rc ) { - log_error_f( db_name, _("error reading free record: %s\n"), - g10_errstr(rc) ); + log_error( _("%s: error reading free record: %s\n"), + db_name, g10_errstr(rc) ); return rc; } /* update dir record */ vr.r.ver.firstfree = rec.r.free.next; rc = tdbio_write_record( &vr ); if( rc ) { - log_error_f( db_name, _("error writing dir record: %s\n"), - g10_errstr(rc) ); + log_error( _("%s: error writing dir record: %s\n"), + db_name, g10_errstr(rc) ); return rc; } /*zero out the new record */ @@ -1173,8 +1194,8 @@ tdbio_new_recnum() rec.recnum = recnum; rc = tdbio_write_record( &rec ); if( rc ) - log_fatal_f(db_name,_("failed to zero a record: %s\n"), - g10_errstr(rc)); + log_fatal(_("%s: failed to zero a record: %s\n"), + db_name, g10_errstr(rc)); } else { /* not found, append a new record */ offset = lseek( db_fd, 0, SEEK_END ); @@ -1203,8 +1224,8 @@ tdbio_new_recnum() } if( rc ) - log_fatal_f(db_name,_("failed to append a record: %s\n"), - g10_errstr(rc)); + log_fatal(_("%s: failed to append a record: %s\n"), + db_name, g10_errstr(rc)); } return recnum ; } @@ -1230,10 +1251,9 @@ tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec ) if( !rc ) { if( pk->local_id && pk->local_id != rec->recnum ) - log_error_f(db_name, - "found record, but LID from memory does " + log_error("%s: found record, but LID from memory does " "not match recnum (%lu,%lu)\n", - pk->local_id, rec->recnum ); + db_name, pk->local_id, rec->recnum ); pk->local_id = rec->recnum; } return rc; @@ -1272,8 +1292,8 @@ tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen, /* Now read the dir record */ rc = tdbio_read_record( recnum, rec, RECTYPE_DIR); if( rc ) - log_error_f(db_name, "can't read dirrec %lu: %s\n", - recnum, g10_errstr(rc) ); + log_error("%s: can't read dirrec %lu: %s\n", + db_name, recnum, g10_errstr(rc) ); } return rc; } diff --git a/g10/tdbio.h b/g10/tdbio.h index 2c52b22b6..68011d48f 100644 --- a/g10/tdbio.h +++ b/g10/tdbio.h @@ -21,6 +21,7 @@ #ifndef G10_TDBIO_H #define G10_TDBIO_H +#include "host2net.h" #define TRUST_RECORD_LEN 40 #define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5) @@ -46,15 +47,14 @@ #define RECTYPE_FREE 254 -#define DIRF_CHECKED 1 /* everything has been checked, the other bits are - valid */ -#define DIRF_MISKEY 2 /* not all signatures are checked */ - /* this flag is used as a quick hint, that we */ - /* do not need to look at the sig records */ -#define DIRF_ERROR 4 /* severe errors: the key is not valid for some reasons - but we mark it to avoid duplicate checks */ +#define DIRF_CHECKED 1 /* has been checkd - other bits are valid */ +#define DIRF_VALID 2 /* This key is valid: There is at least */ + /* 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 KEYF_CHECKED 1 /* This key has been checked */ +#define KEYF_VALID 2 /* This is a valid (sub)key */ #define KEYF_EXPIRED 4 /* this key is expired */ #define KEYF_REVOKED 8 /* this key has been revoked */ @@ -64,6 +64,7 @@ #define SIGF_CHECKED 1 /* signature has been checked - bits 0..6 are valid */ #define SIGF_VALID 2 /* the signature is valid */ +#define SIGF_EXPIRED 4 /* the key of this signature has expired */ #define SIGF_REVOKED 8 /* this signature has been revoked */ #define SIGF_NOPUBKEY 128 /* there is no pubkey for this sig */ @@ -176,22 +177,4 @@ int tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen, int tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec ); -#define buftoulong( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \ - (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3))) -#define buftoushort( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1))) -#define ulongtobuf( p, a ) do { \ - ((byte*)p)[0] = a >> 24; \ - ((byte*)p)[1] = a >> 16; \ - ((byte*)p)[2] = a >> 8; \ - ((byte*)p)[3] = a ; \ - } while(0) -#define ushorttobuf( p, a ) do { \ - ((byte*)p)[0] = a >> 8; \ - ((byte*)p)[1] = a ; \ - } while(0) -#define buftou32( p) buftoulong( (p) ) -#define u32tobuf( p, a) ulongtobuf( (p), (a) ) - - - #endif /*G10_TDBIO_H*/ diff --git a/g10/trustdb.c b/g10/trustdb.c index e4a447826..5f391d028 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -1370,6 +1370,8 @@ update_trustdb( ) else log_info("lid %lu: updated\n", lid_from_keyblock(keyblock) ); + + release_kbnode( keyblock ); keyblock = NULL; } } if( rc && rc != -1 ) @@ -1910,7 +1912,6 @@ upd_key_record( PKT_public_key *pk, TRUSTREC *drec, RECNO_LIST *recno_list ) } if( recno ) { /* yes */ ins_recno_list( recno_list, recno, RECTYPE_KEY ); - /* here we would compare/update the keyflags */ } else { /* no: insert this new key */ memset( &krec, 0, sizeof(krec) ); @@ -2110,6 +2111,8 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec, } } else if( sig->sig_class == 0x18 ) { /* key binding */ + /* get the corresponding key */ + /* FIXME */ } else if( sig->sig_class == 0x20 ) { /* key revocation */ @@ -2427,6 +2430,7 @@ update_trust_record( KBNODE keyblock ) ulong uidrecno = 0; byte uidhash[20]; RECNO_LIST recno_list = NULL; /* list of verified records */ + /* fixme: replace recno_list by a lookup on node->recno */ node = find_kbnode( keyblock, PKT_PUBLIC_KEY ); primary_pk = node->pkt->pkt.public_key; @@ -2459,6 +2463,7 @@ update_trust_record( KBNODE keyblock ) case PKT_SIGNATURE: if( drec.dirty ) { /* upd_sig_recrod may read the drec */ + write_record( &drec ); drec.dirty = 0; } diff --git a/include/ChangeLog b/include/ChangeLog index 9274ee962..6cb61d830 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +Tue Oct 20 11:40:00 1998 Werner Koch (wk@isil.d.shuttle.de) + + * iobuf.h (iobuf_get_temp_buffer): New. + Tue Oct 13 12:40:48 1998 Werner Koch (wk@isil.d.shuttle.de) * iobuf.h (iobuf_get): Now uses .nofast diff --git a/include/distfiles b/include/distfiles index 6257e96ed..191dd880d 100644 --- a/include/distfiles +++ b/include/distfiles @@ -7,6 +7,7 @@ ttyio.h types.h util.h i18n.h +host2net.h g10lib.h diff --git a/include/host2net.h b/include/host2net.h new file mode 100644 index 000000000..4c14d64ce --- /dev/null +++ b/include/host2net.h @@ -0,0 +1,43 @@ +/* host2net.h - Some macros + * Copyright (C) 1998 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 + */ + +#ifndef G10_HOST2NET_H +#define G10_HOST2NET_H + +#include "types.h" + +#define buftoulong( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \ + (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3))) +#define buftoushort( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1))) +#define ulongtobuf( p, a ) do { \ + ((byte*)p)[0] = a >> 24; \ + ((byte*)p)[1] = a >> 16; \ + ((byte*)p)[2] = a >> 8; \ + ((byte*)p)[3] = a ; \ + } while(0) +#define ushorttobuf( p, a ) do { \ + ((byte*)p)[0] = a >> 8; \ + ((byte*)p)[1] = a ; \ + } while(0) +#define buftou32( p) buftoulong( (p) ) +#define u32tobuf( p, a) ulongtobuf( (p), (a) ) + + +#endif /*G10_HOST2NET_H*/ diff --git a/include/iobuf.h b/include/iobuf.h index f09d701fb..8c836cc01 100644 --- a/include/iobuf.h +++ b/include/iobuf.h @@ -71,6 +71,7 @@ int iobuf_debug_mode; IOBUF iobuf_alloc(int usage, size_t bufsize); IOBUF iobuf_temp(void); +IOBUF iobuf_temp_with_content( const char *buffer, size_t length ); IOBUF iobuf_open( const char *fname ); IOBUF iobuf_fopen( const char *fname, const char *mode ); IOBUF iobuf_create( const char *fname ); @@ -129,6 +130,7 @@ int iobuf_in_block_mode( IOBUF a ); #define iobuf_where(a) "[don't know]" #define iobuf_id(a) ((a)->no) +#define iobuf_get_temp_buffer(a) ( (a)->d.buf ) #define iobuf_get_temp_length(a) ( (a)->d.len ) #define iobuf_is_temp(a) ( (a)->usage == 3 ) diff --git a/scripts/autogen.sh b/scripts/autogen.sh index 17905a132..cba5adcc1 100755 --- a/scripts/autogen.sh +++ b/scripts/autogen.sh @@ -9,19 +9,25 @@ if (autoconf --version) < /dev/null > /dev/null 2>&1 ; then else echo echo "**Error**: You must have "\`autoconf\'" installed to compile $PGM." - echo ' (version 2.10 or newer is required' + echo ' (version 2.10 or newer is required)' DIE="yes" fi if (automake --version) < /dev/null > /dev/null 2>&1 ; then if (aclocal --version) < /dev/null > /dev/null 2>&1; then - : + if (aclocal --version | awk 'NR==1 { if( $4 >= 1.3 ) exit 1; exit 0; }'); + then + echo "**Error**: "\`aclocal\'" is too old." + echo ' (version 1.3 or newer is required)' + DIE="yes" + fi else echo echo "**Error**: Missing "\`aclocal\'". The version of "\`automake\' echo " installed doesn't appear recent enough." DIE="yes" fi + else echo echo "**Error**: You must have "\`automake\'" installed to compile $PGM." @@ -40,3 +46,5 @@ automake --gnu; autoheader autoconf +echo "Ready to run ./configure" + diff --git a/tools/Makefile.am b/tools/Makefile.am index e3c8975d3..418df21ca 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,8 +1,8 @@ ## Process this file with automake to produce Makefile.in -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl +INCLUDES = -I$(top_srcdir)/include needed_libs = ../cipher/libcipher.a ../util/libutil.a \ - ../mpi/libmpi.a ../util/libutil.a + ../mpi/libmpi.a ../util/libutil.a @INTLLIBS@ noinst_PROGRAMS = mpicalc bftest clean-sat mk-tdata shmtest @@ -15,10 +15,10 @@ mk_tdata_SOURCES = mk-tdata.c shmtest_SOURCES = shmtest.c -mpicalc_LDADD = @INTLLIBS@ $(needed_libs) -bftest_LDADD = @INTLLIBS@ $(needed_libs) +mpicalc_LDADD = $(needed_libs) +bftest_LDADD = $(needed_libs) -shmtest_LDADD = @INTLLIBS@ $(needed_libs) +shmtest_LDADD = $(needed_libs) mpicalc bftest shmtest: $(needed_libs) diff --git a/util/ChangeLog b/util/ChangeLog index 6904c9333..3c1dba658 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,8 @@ +Wed Oct 21 12:20:29 1998 Werner Koch (wk@isil.d.shuttle.de) + + * util.c (iobuf_flush): autoincreasing of a temp. iobuf + (iobuf_temp_with_content): New. + Tue Oct 13 12:40:13 1998 Werner Koch (wk@isil.d.shuttle.de) * util.c (.nofast): set this variable diff --git a/util/Makefile.am b/util/Makefile.am index eee154ed7..3f2f9a3d0 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -I../intl +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl noinst_LIBRARIES = libutil.a diff --git a/util/iobuf.c b/util/iobuf.c index e4c412444..e1b62cfc2 100644 --- a/util/iobuf.c +++ b/util/iobuf.c @@ -483,6 +483,18 @@ iobuf_temp() return a; } +IOBUF +iobuf_temp_with_content( const char *buffer, size_t length ) +{ + IOBUF a; + + a = iobuf_alloc(3, length ); + memcpy( a->d.buf, buffer, length ); + a->d.len = length; + + return a; +} + /**************** * Create a head iobuf for reading from a file @@ -877,8 +889,19 @@ iobuf_flush(IOBUF a) return 0; /*log_debug("iobuf-%d.%d: flush\n", a->no, a->subno );*/ - if( a->usage == 3 ) - log_bug("temp buffer too short\n"); + if( a->usage == 3 ) { /* must increase the size of the temp buffer */ + char *newbuf; + size_t newsize = a->d.size + 8192; + + log_debug("increasing temp iobuf from %lu to %lu\n", + (ulong)a->d.size, (ulong)newsize ); + newbuf = m_alloc( newsize ); + memcpy( newbuf, a->d.buf, a->d.len ); + m_free(a->d.buf); + a->d.buf = newbuf; + a->d.size = newsize; + return 0; + } else if( a->usage != 2 ) log_bug("flush on non-output iobuf\n"); else if( !a->filter ) diff --git a/util/logger.c b/util/logger.c index 60f59da8a..8183abe5c 100644 --- a/util/logger.c +++ b/util/logger.c @@ -161,7 +161,7 @@ g10_log_bug( const char *fmt, ... ) va_list arg_ptr ; putc('\n', stderr ); - print_prefix("Ooops: "); + print_prefix("Ohhhh jeeee: "); va_start( arg_ptr, fmt ) ; vfprintf(stderr,fmt,arg_ptr) ; va_end(arg_ptr); @@ -174,7 +174,7 @@ g10_log_bug( const char *fmt, ... ) void g10_log_bug0( const char *file, int line, const char *func ) { - log_bug(_("Ohhhh jeeee ... this is a bug (%s:%d:%s)\n"), file, line, func ); + log_bug(_("... this is a bug (%s:%d:%s)\n"), file, line, func ); } #else void