diff --git a/ChangeLog b/ChangeLog index 10c46392b..99547d5dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,15 @@ -Sat Jun 26 12:15:59 CEST 1999 Werner Koch +Tue Jun 29 21:44:25 CEST 1999 Werner Koch + * configure.in (use_local_zlib): The lost dollar is back. + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add EMX case. + * configure.in: Another variant of the MX vendor string + + * configure.in (--with-capabilities): Some test code (Remi). + +Sat Jun 26 12:15:59 CEST 1999 Werner Koch + * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Support for HPUX and IRIX. * configure.in (HAVE_DL_SHL_LOAD): New for HPUX (Dave Dykstra). diff --git a/Makefile.am b/Makefile.am index a16cc0559..b07b909fe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ ## Process this file with automake to produce Makefile.in -#if COMPILE_LIBGCRYPT -#gcrypt = gcrypt -#else +if COMPILE_LIBGCRYPT +gcrypt = gcrypt +else gcrypt = -#endif +endif SUBDIRS = intl zlib util mpi cipher tools g10 po doc checks ${gcrypt} EXTRA_DIST = VERSION PROJECTS BUGS diff --git a/NEWS b/NEWS index 76ba96e63..8e0506502 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ + + * + + Noteworthy changes in version 0.9.8 ----------------------------------- diff --git a/TODO b/TODO index bc8e25be5..49203445b 100644 --- a/TODO +++ b/TODO @@ -6,16 +6,10 @@ * Speed up calculation of key validity. - * See why we always get this "Hmmm, public key not anymore available" - Rewrite that stuff. - * print a warning when a revoked/expired _secret_ key is used. * remove more "Fixmes" - * Use capabilities if available. glibc2 does not support it yet? - What about 2.2 or should we use the system calls directly? - * when decryptiong multiple key: print a warning only if no usable pubkey encrypt package was found. Extension: display a list of all recipients. @@ -29,8 +23,6 @@ * convert the given user ID to UTF-8 and add an option to suppress this. - * A way to disable keys. - Nice to have ------------ diff --git a/VERSION b/VERSION index e3e180701..878e17c7f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.9.8 +0.9.8a diff --git a/acconfig.h b/acconfig.h index 89931d519..ea0d0ff5c 100644 --- a/acconfig.h +++ b/acconfig.h @@ -92,6 +92,7 @@ * with special properties like no file modes */ #undef HAVE_DOSISH_SYSTEM +#undef USE_CAPABILITIES @BOTTOM@ diff --git a/acinclude.m4 b/acinclude.m4 index 4e1645b8d..542995330 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -560,11 +560,20 @@ AC_CHECK_TOOL(AS, as, false) # GNUPG_SYS_SYMBOL_UNDERSCORE - does the compiler prefix global symbols # with an underscore? AC_DEFUN(GNUPG_SYS_SYMBOL_UNDERSCORE, -[if test "$cross_compiling" = yes; then - AC_MSG_CHECKING([for _ prefix in compiled symbols]) - ac_cv_sys_symbol_underscore=yes - AC_MSG_RESULT(assume yes) -else +[ac_cv_sys_symbol_underscore="check" +case "${target}" in + i386-emx-os2 | i[3456]86-pc-os2*emx ) + ac_cv_sys_symbol_underscore=yes + ;; + *) + if test "$cross_compiling" = yes; then + ac_cv_sys_symbol_underscore=yes + fi + ;; +esac + +if test "$ac_cv_sys_symbol_underscore" = "check"; then +ac_cv_sys_symbol_underscore="" AC_REQUIRE([GNUPG_PROG_NM])dnl AC_REQUIRE([GNUPG_SYS_NM_PARSE])dnl AC_MSG_CHECKING([for _ prefix in compiled symbols]) @@ -597,8 +606,10 @@ else fi rm -rf conftest* ]) -AC_MSG_RESULT($ac_cv_sys_symbol_underscore) +else +AC_MSG_CHECKING([for _ prefix in compiled symbols]) fi +AC_MSG_RESULT($ac_cv_sys_symbol_underscore) if test x$ac_cv_sys_symbol_underscore = xyes; then AC_DEFINE(WITH_SYMBOL_UNDERSCORE,1, [define if compiled symbols have a leading underscore]) diff --git a/configure.in b/configure.in index d7ad8ea18..e5d79389d 100644 --- a/configure.in +++ b/configure.in @@ -102,16 +102,25 @@ AC_ARG_WITH(included-zlib, [g10_force_zlib=yes], [g10_force_zlib=no] ) AC_MSG_RESULT($g10_force_zlib) -dnl This does not work because automakes install tareget still needs libtool -dnl dnl -dnl dnl Check wether we want to compile libgcrypt -dnl dnl -dnl AC_MSG_CHECKING([whether compilation of libgcrypt is requested]) -dnl AC_ARG_ENABLE(libgcrypt, -dnl [ --enable-libgcrypt compile the libgcrypt [default=no]], -dnl [compile_libgcrypt="$enableval"],[compile_libgcrypt=no]) -dnl AM_CONDITIONAL(COMPILE_LIBGCRYPT, test x$compile_libgcrypt = xyes) -dnl AC_MSG_RESULT($compile_libgcrypt) +dnl +dnl Check wether we want to compile libgcrypt +dnl +AC_MSG_CHECKING([whether compilation of libgcrypt is requested]) +AC_ARG_ENABLE(libgcrypt, + [ --enable-libgcrypt compile the libgcrypt [default=no]], +[compile_libgcrypt="$enableval"],[compile_libgcrypt=no]) +AM_CONDITIONAL(COMPILE_LIBGCRYPT, test x$compile_libgcrypt = xyes) +AC_MSG_RESULT($compile_libgcrypt) + + +dnl +dnl Check whether we want to use Linux capabilities +dnl +AC_MSG_CHECKING([whether use of capabilities is requested]) +AC_ARG_WITH(capabilities, + [ --with-capabilities use linux capabilities [default=no]], +[use_capabilities="$withval"],[use_capabilities=no]) +AC_MSG_RESULT($use_capabilities) dnl Checks for programs. @@ -135,12 +144,11 @@ AC_CHECK_PROG(DOCBOOK_TO_MAN, docbook-to-man, yes, no) AM_CONDITIONAL(HAVE_DOCBOOK_TO_MAN, test "$ac_cv_prog_DOCBOOK_TO_MAN" = yes) - -dnl if test x$compile_libgcrypt = xyes; then -dnl dnl Don't default to build shared libs -dnl AM_DISABLE_SHARED -dnl AM_PROG_LIBTOOL -dnl fi +dnl +dnl Don't default to build shared libs +dnl +AM_DISABLE_SHARED +AM_PROG_LIBTOOL MPI_OPT_FLAGS="" @@ -165,7 +173,7 @@ case "${target}" in try_gettext="no" try_gdbm="no" ;; - i386-emx-os2 | i[3456]86-pc-os2emx ) + i386-emx-os2 | i[3456]86-pc-os2*emx ) # OS/2 with the EMX environment ac_cv_have_dev_random=no AC_DEFINE(HAVE_DRIVE_LETTERS) @@ -173,6 +181,7 @@ case "${target}" in try_gettext="no" try_gdbm="no" ;; + *-*-hpux*) if test -z "$GCC" ; then CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE" @@ -204,7 +213,7 @@ case "${target}" in i386--mingw32) PRINTABLE_OS_NAME="MingW32" ;; - i386-emx-os2 | i[3456]86-pc-os2emx) + i386-emx-os2 | i[3456]86-pc-os2*emx ) PRINTABLE_OS_NAME="OS/2" ;; *-linux*) @@ -356,12 +365,38 @@ fi dnl Checks for library functions. AC_FUNC_VPRINTF -AC_CHECK_FUNCS(strerror stpcpy strlwr tcgetattr rand strtoul mmap) +AC_CHECK_FUNCS(strerror stpcpy strlwr stricmp tcgetattr rand strtoul mmap) AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit) AC_CHECK_FUNCS(memicmp atexit raise getpagesize strftime nl_langinfo) GNUPG_CHECK_MLOCK +dnl +dnl Check whether we can use Linux capabilities as requested +dnl +if test "$use_capabilities" = "yes" ; then +use_capabilities=no +AC_CHECK_HEADERS(sys/capability.h) +if test "$ac_cv_header_sys_capability_h" = "yes" ; then + AC_CHECK_LIB(cap, cap_init, ac_need_libcap=1) + if test "$ac_cv_lib_cap_cap_init" = "yes"; then + AC_DEFINE(USE_CAPABILITIES) + use_capabilities=yes + fi +fi +if test "$use_capabilities" = "no" ; then + AC_MSG_WARN([[ +*** The use of capabilities on this system is not possible. +*** You need a recent Linux kernel and some patches: +*** fcaps-2.2.9-990610.patch (kernel patch for 2.2.9) +*** fcap-module-990613.tar.gz (kernel module) +*** libcap-1.92.tar.gz (user mode library and utilities) +*** And you have to configure the kernel with CONFIG_VFS_CAP_PLUGIN +*** set (filesystems menu). Be warned: This code is *really* ALPHA.]]) +fi +fi + + GNUPG_CHECK_IPC if test "$ac_cv_header_sys_shm_h" = "yes"; then AC_DEFINE(USE_SHM_COPROCESSING) @@ -415,7 +450,7 @@ if test "$use_static_rnd" = default; then i386--mingw32) static_modules="$static_modules rndw32" ;; - i386-emx-os2|i[3456]86-pc-os2emx) + i386-emx-os2|i[3456]86-pc-os2*emx) static_modules="$static_modules rndos2" ;; m68k-atari-mint) @@ -541,7 +576,7 @@ else fi fi -if test "use_local_zlib" = yes ; then +if test "$use_local_zlib" = yes ; then AM_CONDITIONAL(ENABLE_LOCAL_ZLIB, true) GNUPG_LINK_FILES(zlib/zlib.h, zlib.h ) GNUPG_LINK_FILES(zlib/zconf.h, zconf.h ) diff --git a/debian/changelog b/debian/changelog index ad0164818..903c23012 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,29 @@ +gnupg (0.9.8-1) unstable; urgency=low + + * New upstream version. + * debian/rules (binary-arch): don't create a gpgm manpage as the binary + no longer exists. Noticed by Wichert Akkerman + . [#38864] + + -- James Troup Sun, 27 Jun 1999 01:07:58 +0100 + +gnupg (0.9.7-1) unstable; urgency=low + + * New upstream version. + + -- James Troup Tue, 25 May 1999 13:23:24 +0100 + +gnupg (0.9.6-1) unstable; urgency=low + + * New upstream version. + * debian/copyright: update version number, noticed by Lazarus Long + . + * debian/control (Depends): depend on makedev (>= 2.3.1-13) to ensure + that /dev/urandom exists; reported by Steffen Markert + . [#32076] + + -- James Troup Tue, 11 May 1999 21:06:27 +0100 + gnupg (0.9.5-1) unstable; urgency=low * New upstream version. diff --git a/debian/control b/debian/control index 9e900f8d4..0b6120ea6 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Standards-Version: 2.5.0.0 Package: gnupg Architecture: any -Depends: ${shlibs:Depends} +Depends: ${shlibs:Depends}, makedev (>= 2.3.1-13) Description: GNU privacy guard - a free PGP replacement. GnuPG is the GNU encryption and signing tool. As you can see from the version number, the program may have some bugs and some features may not diff --git a/debian/copyright b/debian/copyright index 9ee053bb2..0ae272dc6 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,14 +4,14 @@ have some bugs and some features may not work at all. This package was put together by me, James Troup , from the sources, which I obtained from -ftp://ftp.gnupg.org/pub/gcrypt/gnupg-0.9.2.tar.gz. The changes were +ftp://ftp.gnupg.org/pub/gcrypt/gnupg-0.9.8.tar.gz. The changes were minimal, namely: - adding support for the Debian package maintenance scheme, by adding various debian/* files. Program Copyright (C) 1998, 1999 Free Software Foundation, Inc. -Modifications for Debian Copyright (C) 1998 James Troup. +Modifications for Debian Copyright (C) 1998,1999 James Troup. GNUPG is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/debian/rules b/debian/rules index 96b966018..e10b1929b 100644 --- a/debian/rules +++ b/debian/rules @@ -1,5 +1,5 @@ #!/usr/bin/make -f -# debian/rules file - for GNUPG (0.9.4) +# debian/rules file - for GNUPG (0.9.8) # Based on sample debian/rules file - for GNU Hello (1.3). # Copyright 1994,1995 by Ian Jackson. # Copyright 1998 James Troup @@ -34,9 +34,7 @@ binary-arch: checkroot build # test install -d debian/tmp/DEBIAN/ install -m 755 debian/preinst debian/tmp/DEBIAN/preinst $(MAKE) prefix=`pwd`/debian/tmp/usr install - rm debian/tmp/usr/man/man1/gpgm.1 gzip -9v debian/tmp/usr/man/man1/* - ln -s gpg.1.gz debian/tmp/usr/man/man1/gpgm.1.gz strip debian/tmp/usr/bin/* strip --strip-unneeded debian/tmp/usr/lib/gnupg/* install -d debian/tmp/usr/doc/gnupg/ diff --git a/doc/DETAILS b/doc/DETAILS index d680a88d9..84b42833b 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -238,8 +238,9 @@ the DB is always of type 2 and this is the only record of this type. 1 byte ownertrust 1 byte dirflag 1 byte maximum validity of all the user ids - 4 byte time of last validity check. - 15 byte reserved + 1 u32 time of last validity check. + 1 u32 Must check when this time has been reached. + (0 = no check required) Record type 3: (key record) diff --git a/doc/FAQ b/doc/FAQ index e22533e55..620b27ef1 100644 --- a/doc/FAQ +++ b/doc/FAQ @@ -191,6 +191,8 @@ u = The key is ultimately trusted; this is only used for keys for which the secret key is also available. + r = The key has been revoked + d = The key has been disabled The value in the "pub" record is the best one of all "uid" records. diff --git a/g10/ChangeLog b/g10/ChangeLog index 96c2c9b5a..9db45bb4a 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,20 @@ +Tue Jun 29 21:44:25 CEST 1999 Werner Koch + + + * trustdb.h (TRUST_FLAG_DISABLED): New. + + * status.c (USE_CAPABILITIES): Capabilities support (Remi). + + * tdbio.c : Added new fields to the DIR record. + (tdbio_write_record): Fixed the update of the hash tables. + (tdbio_delete_record): Drop the record from the hash tables. + (drop_from_hashtbl): New. + + * status.c (cpr_get): Special online help mode. + * helptext.c ("keyedit.cmd"): Removed. + * keyedit.c (keyedit_menu): Use only help system. + (enable_disable_key): New bit doies not yet work. + Sat Jun 26 12:15:59 CEST 1999 Werner Koch diff --git a/g10/helptext.c b/g10/helptext.c index 7e573469a..521df534d 100644 --- a/g10/helptext.c +++ b/g10/helptext.c @@ -146,10 +146,6 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = { }, -{ N_("keyedit.cmd"), - "Please enter \"help\" to see the list of commands." -}, - { N_("keyedit.save.okay"), "Answer \"yes\" or \"no\"" }, diff --git a/g10/keyedit.c b/g10/keyedit.c index 91a4d6bdf..df14f13e1 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -59,6 +59,7 @@ static int count_selected_uids( KBNODE keyblock ); static int count_selected_keys( KBNODE keyblock ); static int menu_revsig( KBNODE keyblock ); static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ); +static int enable_disable_key( KBNODE keyblock, int disable ); #define CONTROL_D ('D' - 'A' + 1) @@ -550,6 +551,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) cmdLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG, cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, + cmdENABLEKEY, cmdDISABLEKEY, cmdNOP }; static struct { const char *name; enum cmdids id; @@ -586,6 +588,8 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) { N_("trust") , cmdTRUST , 0, N_("change the ownertrust") }, { N_("revsig") , cmdREVSIG , 0, N_("revoke signatures") }, { N_("revkey") , cmdREVKEY , 1, N_("revoke a secondary key") }, + { N_("disable") , cmdDISABLEKEY , 0, N_("disable a key") }, + { N_("enable") , cmdENABLEKEY , 0, N_("enable a key") }, { NULL, cmdNONE } }; enum cmdids cmd; @@ -662,7 +666,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) have_commands = 0; } if( !have_commands ) { - answer = cpr_get("keyedit.cmd", _("Command> ")); + answer = cpr_get("", _("Command> ")); cpr_kill_prompt(); } trim_spaces(answer); @@ -842,12 +846,10 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) break; case cmdADDKEY: - secmem_dump_stats(); if( generate_subkeypair( keyblock, sec_keyblock ) ) { redisplay = 1; sec_modified = modified = 1; } - secmem_dump_stats(); break; @@ -934,6 +936,14 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) } break; + case cmdENABLEKEY: + case cmdDISABLEKEY: + if( enable_disable_key( keyblock, cmd == cmdDISABLEKEY ) ) { + redisplay = 1; + modified = 1; + } + break; + default: tty_printf("\n"); tty_printf(_("Invalid command (try \"help\")\n")); @@ -1859,3 +1869,15 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) } +static int +enable_disable_key( KBNODE keyblock, int disable ) +{ + int entire; + int changed = 0; + + + entire = !count_selected_keys( keyblock ); + + return changed; +} + diff --git a/g10/status.c b/g10/status.c index d068a4537..c29f54746 100644 --- a/g10/status.c +++ b/g10/status.c @@ -25,6 +25,9 @@ #include #include #ifdef USE_SHM_COPROCESSING + #ifdef USE_CAPABILITIES + #include + #endif #ifdef HAVE_SYS_IPC_H #include #endif @@ -165,6 +168,9 @@ init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ) log_debug("mapped %uk shared memory at %p, id=%d\n", (unsigned)shm_size/1024, shm_area, shm_id ); if( lock_mem ) { + #ifdef USE_CAPABILITIES + cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); + #endif #ifdef IPC_HAVE_SHM_LOCK if ( shmctl (shm_id, SHM_LOCK, 0) ) log_info("locking shared memory %d failed: %s\n", @@ -181,6 +187,9 @@ init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ) #else log_info("Locking shared memory %d failed: No way to do it\n", shm_id ); #endif + #ifdef USE_CAPABILITIES + cap_set_proc( cap_from_text("cap_ipc_lock+p") ); + #endif } @@ -279,7 +288,7 @@ cpr_get( const char *keyword, const char *prompt ) #endif for(;;) { p = tty_get( prompt ); - if( *p == '?' && !p[1] ) { + if( *p=='?' && !p[1] && !(keyword && !*keyword)) { m_free(p); display_online_help( keyword ); } diff --git a/g10/tdbio.c b/g10/tdbio.c index 39f1d5677..8e5f5d084 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -69,8 +69,8 @@ struct cmp_krec_fpr_struct { int fprlen; }; -/* a type used to pass infomation to cmp_sdir */ -struct cmp_sdir_struct { +/* a type used to pass infomation to cmp_[s]dir */ +struct cmp_xdir_struct { int pubkey_algo; u32 keyid[2]; }; @@ -852,8 +852,9 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum ) return rc; /* ready */ } else { - log_error( "hashtbl %lu points to an invalid record\n", - item); + log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n", + table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); + list_trustdb(NULL); return G10ERR_TRUSTDB; } } @@ -862,6 +863,92 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum ) } +/**************** + * Drop an entry from a hashtable + * table gives the start of the table, key and keylen is the key, + */ +static int +drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum ) +{ + TRUSTREC rec; + ulong hashrec, item; + int msb; + int level=0; + int rc, i; + + hashrec = table; + next_level: + msb = key[level]; + hashrec += msb / ITEMS_PER_HTBL_RECORD; + rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL ); + if( rc ) { + log_error( db_name, "drop_from_hashtable: read failed: %s\n", + g10_errstr(rc) ); + return rc; + } + + item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; + if( !item ) /* not found - forget about it */ + return 0; + + if( item == recnum ) { /* tables points direct to the record */ + rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = 0; + rc = tdbio_write_record( &rec ); + if( rc ) + log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n", + g10_errstr(rc) ); + return rc; + } + + rc = tdbio_read_record( item, &rec, 0 ); + if( rc ) { + log_error( "drop_from_hashtable: read item failed: %s\n", + g10_errstr(rc) ); + return rc; + } + + if( rec.rectype == RECTYPE_HTBL ) { + hashrec = item; + level++; + if( level >= keylen ) { + log_error( "hashtable has invalid indirections.\n"); + return G10ERR_TRUSTDB; + } + goto next_level; + } + + if( rec.rectype == RECTYPE_HLST ) { + for(;;) { + for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { + if( rec.r.hlst.rnum[i] == recnum ) { + rec.r.hlst.rnum[i] = 0; /* drop */ + rc = tdbio_write_record( &rec ); + if( rc ) + log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n", + g10_errstr(rc) ); + return rc; + } + } + if( rec.r.hlst.next ) { + rc = tdbio_read_record( rec.r.hlst.next, + &rec, RECTYPE_HLST); + if( rc ) { + log_error( "scan keyhashtbl read hlst failed: %s\n", + g10_errstr(rc) ); + return rc; + } + } + else + return 0; /* key not in table */ + } + } + + log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n", + table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); + return G10ERR_TRUSTDB; +} + + /**************** * Lookup a record via the hashtable tablewith key/keylen and return the @@ -973,6 +1060,30 @@ update_sdirhashtbl( TRUSTREC *sr ) return upd_hashtable( get_sdirhashrec(), key, 8, sr->recnum ); } +/**************** + * Drop the records from the key-hashtbl + */ +static int +drop_from_keyhashtbl( TRUSTREC *kr ) +{ + return drop_from_hashtable( get_keyhashrec(), + kr->r.key.fingerprint, + kr->r.key.fingerprint_len, kr->recnum ); +} + +/**************** + * Drop record drom the shadow dir hashtbl + */ +static int +drop_from_sdirhashtbl( TRUSTREC *sr ) +{ + byte key[8]; + + u32tobuf( key , sr->r.sdir.keyid[0] ); + u32tobuf( key+4 , sr->r.sdir.keyid[1] ); + return drop_from_hashtable( get_sdirhashrec(), key, 8, sr->recnum ); +} + @@ -1009,6 +1120,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp ) if( rec->r.dir.valcheck ) fprintf( fp, ", v=%02x/%s", rec->r.dir.validity, strtimestamp(rec->r.dir.valcheck) ); + if( rec->r.dir.checkat ) + fprintf( fp, ", a=%s", strtimestamp(rec->r.dir.checkat) ); if( rec->r.dir.dirflags & DIRF_CHECKED ) { if( rec->r.dir.dirflags & DIRF_VALID ) fputs(", valid", fp ); @@ -1071,7 +1184,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp ) 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_VALID) ? 'V': + (rec->r.sig.sig[i].flag & SIGF_IGNORED) ? 'I':'-', (rec->r.sig.sig[i].flag & SIGF_EXPIRED) ? 'E':'-', (rec->r.sig.sig[i].flag & SIGF_REVOKED) ? 'R':'-'); } @@ -1196,6 +1310,7 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) rec->r.dir.dirflags = *p++; rec->r.dir.validity = *p++; rec->r.dir.valcheck = buftoulong(p); p += 4; + rec->r.dir.checkat = buftoulong(p); p += 4; switch( rec->r.dir.validity ) { case 0: case TRUST_UNDEFINED: @@ -1346,6 +1461,7 @@ tdbio_write_record( TRUSTREC *rec ) *p++ = rec->r.dir.dirflags; *p++ = rec->r.dir.validity; ulongtobuf(p, rec->r.dir.valcheck); p += 4; + ulongtobuf(p, rec->r.dir.checkat); p += 4; assert( rec->r.dir.lid == recnum ); break; @@ -1419,7 +1535,7 @@ tdbio_write_record( TRUSTREC *rec ) rc = put_record_into_cache( recnum, buf ); if( rc ) ; - if( rec->rectype == RECTYPE_KEY ) + else if( rec->rectype == RECTYPE_KEY ) rc = update_keyhashtbl( rec ); else if( rec->rectype == RECTYPE_SDIR ) rc = update_sdirhashtbl( rec ); @@ -1433,6 +1549,19 @@ tdbio_delete_record( ulong recnum ) TRUSTREC vr, rec; int rc; + /* Must read the record fist, so we can drop it from the hash tables */ + rc = tdbio_read_record( recnum, &rec, 0 ); + if( rc ) + ; + else if( rec.rectype == RECTYPE_KEY ) + rc = drop_from_keyhashtbl( &rec ); + else if( rec.rectype == RECTYPE_SDIR ) + rc = drop_from_sdirhashtbl( &rec ); + + if( rc ) + return rc; + + /* now we can chnage it to a free record */ rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); if( rc ) log_fatal( _("%s: error reading version record: %s\n"), @@ -1595,7 +1724,7 @@ tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen, static int cmp_sdir( void *dataptr, const TRUSTREC *rec ) { - const struct cmp_sdir_struct *d = dataptr; + const struct cmp_xdir_struct *d = dataptr; return rec->rectype == RECTYPE_SDIR && ( !d->pubkey_algo || rec->r.sdir.pubkey_algo == d->pubkey_algo ) @@ -1607,7 +1736,7 @@ cmp_sdir( void *dataptr, const TRUSTREC *rec ) int tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec ) { - struct cmp_sdir_struct cmpdata; + struct cmp_xdir_struct cmpdata; int rc; byte key[8]; diff --git a/g10/tdbio.h b/g10/tdbio.h index ca9d23e8b..a64f21b5f 100644 --- a/g10/tdbio.h +++ b/g10/tdbio.h @@ -66,6 +66,7 @@ #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_IGNORED 64 /* this signature is ignored by the system */ #define SIGF_NOPUBKEY 128 /* there is no pubkey for this sig */ struct trust_record { @@ -97,8 +98,9 @@ struct trust_record { ulong cacherec; /* the cache record */ byte ownertrust; byte dirflags; - byte validity; /* calculated trustlevel over all uids */ - ulong valcheck; /* timestamp of last validation check */ + byte validity; /* calculated trustlevel over all uids */ + ulong valcheck; /* timestamp of last validation check */ + ulong checkat; /* Check key when this time has been reached*/ } dir; struct { /* primary public key record */ ulong lid; @@ -187,6 +189,7 @@ ulong tdbio_new_recnum(void); int tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec ); int tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen, int pubkey_algo, TRUSTREC *rec ); +int tdbio_search_dir( u32 *keyid, int pubkey_algo, TRUSTREC *rec ); int tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec ); void tdbio_invalid(void); diff --git a/g10/trustdb.c b/g10/trustdb.c index 9f12757b1..1e804d704 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -125,12 +125,6 @@ static int do_check( TRUSTREC *drec, unsigned *trustlevel, unsigned *retflgs); static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec ); -static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig ); -static void upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid, - TRUSTREC *drec, RECNO_LIST *recno_list, int recheck, - TRUSTREC *urec, const byte *uidhash, int revoked, - int *mod_up, int *mod_down ); - /* a table used to keep track of ultimately trusted keys * which are the ones from our secrings and the trusted keys */ static LOCAL_ID_TABLE ultikey_table; @@ -213,42 +207,6 @@ do_sync(void) ***************** helpers ****************** **********************************************/ -/**************** - * Insert a new item into a recno list - */ -static void -ins_recno_list( RECNO_LIST *head, ulong recno, int type ) -{ - RECNO_LIST item = m_alloc( sizeof *item ); - - item->recno = recno; - item->type = type; - item->next = *head; - *head = item; -} - -static RECNO_LIST -qry_recno_list( RECNO_LIST list, ulong recno, int type ) -{ - for( ; list; list = list->next ) { - if( list->recno == recno && (!type || list->type == type) ) - return list; - } - return NULL; -} - - -static void -rel_recno_list( RECNO_LIST *head ) -{ - RECNO_LIST r, r2; - - for(r = *head; r; r = r2 ) { - r2 = r->next; - m_free(r); - } - *head = NULL; -} static LOCAL_ID_TABLE new_lid_table(void) @@ -449,7 +407,9 @@ get_dir_record( PKT_public_key *pk, TRUSTREC *rec ) * Get the LID of a public key. * Returns: The LID of the key (note, that this may be a shadow dir) * or 0 if not available. + * fixme: make this ftser by putting entries into the sdir hash table */ +#if 0 static ulong lid_from_keyid( u32 *keyid ) { @@ -479,6 +439,29 @@ lid_from_keyid( u32 *keyid ) free_public_key( pk ); return lid; } +#endif + +static ulong +lid_from_keyid_no_sdir( u32 *keyid ) +{ + PKT_public_key *pk = m_alloc_clear( sizeof *pk ); + TRUSTREC rec; + ulong lid = 0; + int rc; + + rc = get_pubkey( pk, keyid ); + if( !rc ) { + if( pk->local_id ) + lid = pk->local_id; + else { + rc = tdbio_search_dir_bypk( pk, &rec ); + if( !rc ) + lid = rec.recnum; + } + } + free_public_key( pk ); + return lid; +} @@ -833,226 +816,19 @@ dump_tn_tree_with_colons( int level, TN tree ) ************* trustdb maintenance *********** ***********************************************/ - -static void -check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash, - TRUSTREC *sigrec, int sigidx, ulong hint_owner ) -{ - KBNODE node; - int rc, state; - byte uhash[20]; - int is_selfsig; - PKT_signature *sigpkt = NULL; - TRUSTREC tmp; - u32 sigkid[2]; - int revoked = 0; - - if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED ) - log_info(_("NOTE: sig rec %lu[%d] in hintlist " - "of %lu but marked as checked\n"), - sigrec->recnum, sigidx, hint_owner ); - if( !(sigrec->r.sig.sig[sigidx].flag & SIGF_NOPUBKEY) ) - log_info(_("NOTE: sig rec %lu[%d] in hintlist " - "of %lu but not marked\n"), - sigrec->recnum, sigidx, hint_owner ); - - read_record( sigrec->r.sig.sig[sigidx].lid, &tmp, 0 ); - if( tmp.rectype != RECTYPE_DIR ) { - /* we need the dir record */ - log_error(_("sig rec %lu[%d] in hintlist " - "of %lu does not point to a dir record\n"), - sigrec->recnum, sigidx, hint_owner ); - return; - } - if( !tmp.r.dir.keylist ) { - log_error(_("lid %lu: no primary key\n"), tmp.r.dir.lid ); - return; - } - read_record(tmp.r.dir.keylist, &tmp, RECTYPE_KEY ); - keyid_from_fingerprint( tmp.r.key.fingerprint, - tmp.r.key.fingerprint_len, sigkid ); - - - /* find the correct signature packet */ - state = 0; - for( node=keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) { - PKT_user_id *uidpkt = node->pkt->pkt.user_id; - - if( state ) - break; - rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len ); - if( !memcmp( uhash, uidrec_hash, 20 ) ) - state = 1; - } - else if( state && node->pkt->pkttype == PKT_SIGNATURE ) { - sigpkt = node->pkt->pkt.signature; - if( sigpkt->keyid[0] == sigkid[0] - && sigpkt->keyid[1] == sigkid[1] - && ( (sigpkt->sig_class&~3) == 0x10 - || ( revoked = (sigpkt->sig_class == 0x30)) ) ) { - state = 2; - break; /* found */ - } - } - } - - if( !node ) { - log_info(_("lid %lu: user id not found in keyblock\n"), lid ); - return ; - } - if( state != 2 ) { - log_info(_("lid %lu: user id without signature\n"), lid ); - return ; - } - - /* and check the sig */ - rc = check_key_signature( keyblock, node, &is_selfsig ); - if( is_selfsig ) { - log_error(_("lid %lu: self-signature in hintlist\n"), lid ); - return; - } - - /* FiXME: handling fo SIGF_REVOKED is not correct! */ - - if( !rc ) { /* valid signature */ - if( opt.verbose ) - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uhash[18], uhash[19], - (ulong)sigpkt->keyid[1], - revoked? _("Valid certificate revocation") - : _("Good certificate") ); - sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID; - if( revoked ) - sigrec->r.sig.sig[sigidx].flag |= SIGF_REVOKED; - } - else if( rc == G10ERR_NO_PUBKEY ) { - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uhash[18], uhash[19], - (ulong)sigpkt->keyid[1], - _("very strange: no public key\n") ); - sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY; - } - else { - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uhash[18], uhash[19], - (ulong)sigpkt->keyid[1], g10_errstr(rc) ); - sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED; - } - sigrec->dirty = 1; -} - - -/**************** - * Process a hintlist. - * Fixme: this list is not anymore anchored to another - * record, so it should be put elsewehere in case of an error - * FIXME: add mod_up/down handling - */ -static void -process_hintlist( ulong hintlist, ulong hint_owner ) -{ - ulong hlst_rn; - int rc; - - for( hlst_rn = hintlist; hlst_rn; ) { - TRUSTREC hlstrec; - int hlst_idx; - - read_record( hlst_rn, &hlstrec, RECTYPE_HLST ); - - for( hlst_idx=0; hlst_idx < ITEMS_PER_HLST_RECORD; hlst_idx++ ) { - TRUSTREC dirrec; - TRUSTREC uidrec; - TRUSTREC tmprec; - KBNODE keyblock = NULL; - u32 keyid[2]; - ulong lid; - ulong r1, r2; - - lid = hlstrec.r.hlst.rnum[hlst_idx]; - if( !lid ) - continue; - - read_record( lid, &dirrec, 0 ); - /* make sure it points to a dir record: - * this should be true because it only makes sense to - * call this function if the dir record is available */ - if( dirrec.rectype != RECTYPE_DIR ) { - log_error(_("hintlist %lu[%d] of %lu " - "does not point to a dir record\n"), - hlst_rn, hlst_idx, hint_owner ); - continue; - } - if( !dirrec.r.dir.keylist ) { - log_error(_("lid %lu does not have a key\n"), lid ); - continue; - } - - /* get the keyblock */ - read_record( dirrec.r.dir.keylist, &tmprec, RECTYPE_KEY ); - rc = get_keyblock_byfprint( &keyblock, - tmprec.r.key.fingerprint, - tmprec.r.key.fingerprint_len ); - if( rc ) { - log_error(_("lid %lu: can't get keyblock: %s\n"), - lid, g10_errstr(rc) ); - continue; - } - keyid_from_fingerprint( tmprec.r.key.fingerprint, - tmprec.r.key.fingerprint_len, keyid ); - - /* Walk over all user ids and their signatures and check all - * the signature which are created by hint_owner */ - for( r1 = dirrec.r.dir.uidlist; r1; r1 = uidrec.r.uid.next ) { - TRUSTREC sigrec; - - read_record( r1, &uidrec, RECTYPE_UID ); - for( r2 = uidrec.r.uid.siglist; r2; r2 = sigrec.r.sig.next ) { - int i; - - read_record( r2, &sigrec, RECTYPE_SIG ); - sigrec.dirty = 0; - for(i=0; i < SIGS_PER_RECORD; i++ ) { - if( !sigrec.r.sig.sig[i].lid ) - continue; /* skip deleted sigs */ - if( sigrec.r.sig.sig[i].lid != hint_owner ) - continue; /* not for us */ - /* some diagnostic messages */ - /* and do the signature check */ - check_hint_sig( lid, keyblock, keyid, - uidrec.r.uid.namehash, - &sigrec, i, hint_owner ); - } - if( sigrec.dirty ) - write_record( &sigrec ); - } - } - release_kbnode( keyblock ); - } /* loop over hlst entries */ - - /* delete this hlst record */ - hlst_rn = hlstrec.r.hlst.next; - delete_record( hlstrec.recnum ); - } /* loop over hintlist */ -} - - /**************** * Create or update shadow dir record and return the LID of the record */ static ulong -create_shadow_dir( PKT_signature *sig, ulong lid ) +create_shadow_dir( PKT_signature *sig ) { - TRUSTREC sdir, hlst, tmphlst; - ulong recno, newlid; - int tmpidx=0; /* avoids gcc warnign - this is controlled by tmphlst */ + TRUSTREC sdir; 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)); + log_error(_("tdbio_search_sdir failed: %s\n"), g10_errstr(rc)); tdbio_invalid(); } if( rc == -1 ) { /* not found: create */ @@ -1063,415 +839,26 @@ create_shadow_dir( PKT_signature *sig, ulong lid ) 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; + return sdir.recnum; } -/**************** - * This function checks the given public key and inserts or updates - * the keyrecord from the trustdb. Revocation certificates - * are handled here and the keybinding of subkeys is checked. - * Hmmm: Should we check here, that the key has at least one valid - * user ID or do we allow keys w/o user ID? - * - * keyblock points to the first node in the keyblock, - * keynode is the node with the public key to check - * (either primary or secondary), keyid is the keyid of - * the primary key, drec is the directory record and recno_list - * is a list used to keep track of visited records. - * Existing keyflags are recalculated if recheck is true. - */ -static void -upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid, - TRUSTREC *drec, RECNO_LIST *recno_list, int recheck ) +static ulong +find_or_create_lid( PKT_signature *sig ) { - TRUSTREC krec; - KBNODE node; - PKT_public_key *pk = keynode->pkt->pkt.public_key; - ulong lid = drec->recnum; - byte fpr[MAX_FINGERPRINT_LEN]; - size_t fprlen; - ulong recno, newrecno; - int keybind_seen = 0; - int revoke_seen = 0; - int rc; + ulong lid; - fingerprint_from_pk( pk, fpr, &fprlen ); - /* do we already have this key? */ - for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) { - read_record( recno, &krec, RECTYPE_KEY ); - if( krec.r.key.fingerprint_len == fprlen - && !memcmp( krec.r.key.fingerprint, fpr, fprlen ) ) - break; - } - if( recno ) { /* yes */ - ins_recno_list( recno_list, recno, RECTYPE_KEY ); - } - else { /* no: insert this new key */ - recheck = 1; /* same as recheck */ - memset( &krec, 0, sizeof(krec) ); - krec.rectype = RECTYPE_KEY; - krec.r.key.lid = lid; - krec.r.key.pubkey_algo = pk->pubkey_algo; - krec.r.key.fingerprint_len = fprlen; - memcpy(krec.r.key.fingerprint, fpr, fprlen ); - krec.recnum = newrecno = tdbio_new_recnum(); - write_record( &krec ); - ins_recno_list( recno_list, newrecno, RECTYPE_KEY ); - /* and put this new record at the end of the keylist */ - if( !(recno=drec->r.dir.keylist) ) { - /* this is the first key */ - drec->r.dir.keylist = newrecno; - drec->dirty = 1; - } - else { /* we already have a key, append the new one */ - TRUSTREC save = krec; - for( ; recno; recno = krec.r.key.next ) - read_record( recno, &krec, RECTYPE_KEY ); - krec.r.key.next = newrecno; - write_record( &krec ); - krec = save; - } - } - - if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) ) - return; - - /* check keybindings and revocations */ - krec.r.key.keyflags = 0; - if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) { - /* we assume that a primary key is always valid - * and check later whether we have a revocation */ - krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID; - } - - for( node=keynode->next; node; node = node->next ) { - PKT_signature *sig; - - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - break; /* ready (we check only one key at a time) */ - else if( node->pkt->pkttype != PKT_SIGNATURE ) - continue; - - sig = node->pkt->pkt.signature; - - if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] ) - continue; /* here we only care about a self-signatures */ - - if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */ - if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) - continue; /* oops, ignore subkey binding on main key */ - - /* we check until we find a valid keybinding */ - rc = check_key_signature( keyblock, node, NULL ); - if( !rc ) { - if( opt.verbose ) - log_info(_( - "key %08lX.%lu: Good subkey binding\n"), - (ulong)keyid_from_pk(pk,NULL), lid ); - krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID; - } - else { - log_info(_( - "key %08lX.%lu: Invalid subkey binding: %s\n"), - (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); - krec.r.key.keyflags |= KEYF_CHECKED; - krec.r.key.keyflags &= ~KEYF_VALID; - } - keybind_seen = 1; - } - else if( sig->sig_class == 0x20 && !revoke_seen ) { - if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - continue; /* a subkey is not expected here */ - - /* This is a key revocation certificate: check it */ - rc = check_key_signature( keyblock, node, NULL ); - if( !rc ) { - if( opt.verbose ) - log_info(_( - "key %08lX.%lu: Valid key revocation\n"), - (ulong)keyid_from_pk(pk,NULL), lid ); - krec.r.key.keyflags |= KEYF_REVOKED; - } - else { - log_info(_( - "key %08lX.%lu: Invalid key revocation: %s\n"), - (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); - } - revoke_seen = 1; - } - else if( sig->sig_class == 0x28 && !revoke_seen ) { - if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) - continue; /* a mainkey is not expected here */ - /* This is a subkey revocation certificate: check it */ - /* fixme: we should also check the revocation - * is newer than the key (OpenPGP) */ - rc = check_key_signature( keyblock, node, NULL ); - if( !rc ) { - if( opt.verbose ) - log_info(_( - "key %08lX.%lu: Valid subkey revocation\n"), - (ulong)keyid_from_pk(pk,NULL), lid ); - krec.r.key.keyflags |= KEYF_REVOKED; - } - else { - log_info(_( - "key %08lX.%lu: Invalid subkey binding: %s\n"), - (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); - } - revoke_seen = 1; - } - } - - write_record( &krec ); + lid = lid_from_keyid_no_sdir( sig->keyid ); + if( !lid ) + lid = create_shadow_dir( sig ); + return lid; } -/**************** - * This function checks the given user ID and inserts or updates - * the uid record of the trustdb. Revocation certificates - * are handled here. - * - * keyblock points to the first node in the keyblock, - * uidnode is the node with the user id to check - * keyid is the keyid of - * the primary key, drec is the directory record and recno_list - * is a list used to keep track of visited records. - * Existing uidflags are recalculated if recheck is true. - */ -static void -upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid, - TRUSTREC *drec, RECNO_LIST *recno_list, - int recheck, int *mod_up, int *mod_down ) -{ - ulong lid = drec->recnum; - PKT_user_id *uid = uidnode->pkt->pkt.user_id; - TRUSTREC urec; - PKT_signature *selfsig = NULL; - byte uidhash[20]; - KBNODE node; - ulong recno, newrecno; - int rc; - - if( DBG_TRUST ) - log_debug("upd_uid_record for %08lX/%02X%02X\n", - (ulong)keyid[1], uidhash[18], uidhash[19]); - - /* see whether we already have an uid record */ - rmd160_hash_buffer( uidhash, uid->name, uid->len ); - for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) { - read_record( recno, &urec, RECTYPE_UID ); - if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) ) - break; - } - if( recno ) { /* we already have this record */ - ins_recno_list( recno_list, recno, RECTYPE_UID ); - } - else { /* new user id */ - recheck = 1; /* insert is the same as a recheck */ - memset( &urec, 0 , sizeof(urec) ); - urec.rectype = RECTYPE_UID; - urec.r.uid.lid = drec->recnum; - memcpy(urec.r.uid.namehash, uidhash, 20 ); - urec.recnum = newrecno = tdbio_new_recnum(); - write_record( &urec ); - ins_recno_list( recno_list, newrecno, RECTYPE_UID ); - /* and put this new record at the end of the uidlist */ - if( !(recno=drec->r.dir.uidlist) ) { /* this is the first uid */ - drec->r.dir.uidlist = newrecno; - drec->dirty = 1; - } - else { /* we already have an uid, append it to the list */ - TRUSTREC save = urec; - for( ; recno; recno = urec.r.key.next ) - read_record( recno, &urec, RECTYPE_UID ); - urec.r.uid.next = newrecno; - write_record( &urec ); - urec = save; - } - } - - if( recheck || !(urec.r.uid.uidflags & UIDF_CHECKED) ) { - unsigned orig_uidflags = urec.r.uid.uidflags; - - urec.r.uid.uidflags = 0; - /* first check regular self signatures */ - for( node=uidnode->next; node; node = node->next ) { - PKT_signature *sig; - - if( node->pkt->pkttype == PKT_USER_ID ) - break; /* ready */ - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - break; /* ready */ - if( node->pkt->pkttype != PKT_SIGNATURE ) - continue; - - sig = node->pkt->pkt.signature; - - if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] ) - continue; /* not a self signature */ - - if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */ - rc = check_key_signature( keyblock, node, NULL ); - if( !rc ) { - if( opt.verbose ) - log_info( "uid %08lX.%lu/%02X%02X: %s\n", - (ulong)keyid[1], lid, uidhash[18], uidhash[19], - _("Good self-signature") ); - urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID; - if( !selfsig ) - selfsig = sig; /* use the first valid sig */ - else if( sig->timestamp > selfsig->timestamp - && sig->sig_class >= selfsig->sig_class ) - selfsig = sig; /* but this one is newer */ - } - else { - log_info( "uid %08lX/%02X%02X: %s: %s\n", - (ulong)keyid[1], uidhash[18], uidhash[19], - _("Invalid self-signature"), - g10_errstr(rc) ); - urec.r.uid.uidflags |= UIDF_CHECKED; - } - } - } - - /* and now check for revocations- we must do this after the - * self signature check because a selfsignature which is newer - * than a revocation makes the revocation invalid. - * Fixme: Is this correct - check with rfc2440 - */ - for( node=uidnode->next; node; node = node->next ) { - PKT_signature *sig; - - if( node->pkt->pkttype == PKT_USER_ID ) - break; /* ready */ - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - break; /* ready */ - if( node->pkt->pkttype != PKT_SIGNATURE ) - continue; - - sig = node->pkt->pkt.signature; - - if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] ) - continue; /* not a self signature */ - - if( sig->sig_class == 0x30 ) { /* cert revocation */ - rc = check_key_signature( keyblock, node, NULL ); - if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) { - log_info( "uid %08lX.%lu/%02X%02X: %s\n", - (ulong)keyid[1], lid, uidhash[18], uidhash[19], - _("Valid user ID revocation skipped " - "due to a newer self signature\n") ); - } - else if( !rc ) { - if( opt.verbose ) - log_info( "uid %08lX.%lu/%02X%02X: %s\n", - (ulong)keyid[1], lid, uidhash[18], uidhash[19], - _("Valid user ID revocation\n") ); - urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID; - urec.r.uid.uidflags |= UIDF_REVOKED; - } - else { - log_info("uid %08lX/%02X%02X: %s: %s\n", - (ulong)keyid[1], uidhash[18], uidhash[19], - _("Invalid user ID revocation"), - g10_errstr(rc) ); - } - } - - } - - if( orig_uidflags != urec.r.uid.uidflags ) { - write_record( &urec ); - if( !( urec.r.uid.uidflags & UIDF_VALID ) - || ( urec.r.uid.uidflags & UIDF_REVOKED ) ) - *mod_down=1; - else - *mod_up=1; /*(maybe a new user id)*/ - /* Hmmm, did we catch changed expiration dates? */ - } - - } /* end check self-signatures */ - - - if( (urec.r.uid.uidflags & (UIDF_CHECKED|UIDF_VALID)) - != (UIDF_CHECKED|UIDF_VALID) ) - return; /* user ID is not valid, so no need to check more things */ - - /* check the preferences */ - if( selfsig ) - upd_pref_record( &urec, keyid, selfsig ); - - /* Now we va check the certication signatures */ - for( node=uidnode->next; node; node = node->next ) { - PKT_signature *sig; - - if( node->pkt->pkttype == PKT_USER_ID ) - break; /* ready */ - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - break; /* ready */ - if( node->pkt->pkttype != PKT_SIGNATURE ) - continue; - - sig = node->pkt->pkt.signature; - - if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] ) - continue; /* here we skip the self-signatures */ - - if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */ - upd_cert_record( keyblock, node, keyid, drec, recno_list, - recheck, &urec, uidhash, 0, mod_up, mod_down ); - } - else if( sig->sig_class == 0x30 ) { /* cert revocation */ - upd_cert_record( keyblock, node, keyid, drec, recno_list, - recheck, &urec, uidhash, 1, mod_up, mod_down ); - } - } /* end check certificates */ - - write_record( &urec ); -} - +#if 0 static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig ) { @@ -1586,264 +973,463 @@ upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig ) urec->r.uid.prefrec = prec.recnum; urec->dirty = 1; } +#endif -static void -upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid, - TRUSTREC *drec, RECNO_LIST *recno_list, int recheck, - TRUSTREC *urec, const byte *uidhash, int revoked, - int *mod_up, int *mod_down ) +/**************** + * Check the validity of a key and calculate the keyflags + * keynode points to + * a node with a [sub]key. mainkid has the key ID of the primary key + * keyblock is the complete keyblock which is needed for signature + * checking. LID and PK is only used in verbose mode. + */ +static unsigned int +check_keybinding( KBNODE keyblock, KBNODE keynode, u32 *mainkid, + ulong lid, PKT_public_key *pk ) { - /* We simply insert the signature into the sig records but - * avoid duplicate ones. We do not check them here because - * there is a big chance, that we import required public keys - * later. The problem with this is that we must somewhere store - * the information about this signature (we need a record id). - * We do this by using the record type shadow dir, which will - * be converted to a dir record as when the missing public key - * gets inserted into the trustdb. - */ - ulong lid = drec->recnum; - PKT_signature *sig = signode->pkt->pkt.signature; - TRUSTREC rec; - ulong recno; - TRUSTREC delrec; - int delrecidx=0; - int newflag = 0; - ulong newlid = 0; - ulong pk_lid = 0; - int found_sig = 0; - int found_delrec = 0; + KBNODE node; + int keybind_seen = 0; + int revoke_seen = 0; + unsigned int keyflags=0; + int is_main = (keynode->pkt->pkttype == PKT_PUBLIC_KEY); int rc; + if( is_main ) { + /* a primary key is always valid (user IDs are handled elsewhere)*/ + keyflags = KEYF_CHECKED | KEYF_VALID; + } - if( DBG_TRUST ) - log_debug("upd_cert_record for %08lX.?/%02X%02X/%08lX\n", - (ulong)keyid[1], uidhash[18], - uidhash[19], (ulong)sig->keyid[1] ); + for( node=keynode->next; node; node = node->next ) { + PKT_signature *sig; - delrec.recnum = 0; + if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + break; /* ready */ + if( node->pkt->pkttype != PKT_SIGNATURE ) + continue; /* don't care about other packets */ - /* get the LID of the pubkey of the signature under verification */ - pk_lid = lid_from_keyid( sig->keyid ); + sig = node->pkt->pkt.signature; - /* 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; + if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] ) + continue; /* we only care about self-signatures */ - read_record( recno, &rec, RECTYPE_SIG ); - for(i=0; i < SIGS_PER_RECORD; i++ ) { - TRUSTREC tmp; - if( !rec.r.sig.sig[i].lid ) { - /* (remember this unused slot) */ - if( !found_delrec && !delrec.recnum ) { - delrec = rec; - delrecidx = i; - found_delrec=1; - } - continue; /* skip unused slots */ - } - - if( rec.r.sig.sig[i].lid == pk_lid ) { - if( found_sig ) { - log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1], - _("duplicated certificate - deleted") ); - rec.r.sig.sig[i].lid = 0; - rec.dirty = 1; - continue; - } - found_sig = 1; - } - if( !recheck && !revoked && (rec.r.sig.sig[i].flag & SIGF_CHECKED)) - continue; /* we already checked this signature */ - if( !recheck && (rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) ) - continue; /* we do not have the public key */ - - read_record( rec.r.sig.sig[i].lid, &tmp, 0 ); - if( tmp.rectype == RECTYPE_DIR ) { - /* the public key is in the trustdb: check sig */ - rc = check_key_signature( keyblock, signode, NULL ); - if( !rc ) { /* valid signature */ - if( opt.verbose ) - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1], - revoked? _("Valid certificate revocation") - : _("Good certificate") ); - rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID; - if( revoked ) { /* we are investigating revocations */ - rec.r.sig.sig[i].flag |= SIGF_REVOKED; - *mod_down = 1; - } - else - *mod_up = 1; - } - else if( rc == G10ERR_NO_PUBKEY ) { - /* This may happen if the key is still in the trustdb - * but not available in the keystorage */ - if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) ) - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1], - _("public key not anymore available") ); - rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; - *mod_down = 1; - if( revoked ) - rec.r.sig.sig[i].flag |= SIGF_REVOKED; - } - else { - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n", - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1], - revoked? _("Invalid certificate revocation") - : _("Invalid certificate"), - g10_errstr(rc)); - rec.r.sig.sig[i].flag = SIGF_CHECKED; - if( revoked ) { - rec.r.sig.sig[i].flag |= SIGF_REVOKED; - *mod_down = 1; - } - } - rec.dirty = 1; - } - else if( tmp.rectype == RECTYPE_SDIR ) { - /* must check that it is the right one */ - if( tmp.r.sdir.keyid[0] == sig->keyid[0] - && tmp.r.sdir.keyid[1] == sig->keyid[1] - && (!tmp.r.sdir.pubkey_algo - || tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) { - if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) ) - log_info(_("uid %08lX.%lu/%02X%02X: " - "has shadow dir %lu but is not yet marked.\n"), - (ulong)keyid[1], lid, - uidhash[18], uidhash[19], tmp.recnum ); - rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; - if( revoked ) - rec.r.sig.sig[i].flag |= SIGF_REVOKED; - rec.dirty = 1; - /* fixme: should we verify that the record is - * in the hintlist? - This case here should anyway - * never occur */ - } + if( sig->sig_class == 0x18 && !keybind_seen && !is_main ) { + /* check until we find a valid keybinding */ + rc = check_key_signature( keyblock, node, NULL ); + if( !rc ) { + if( opt.verbose ) + log_info(_("key %08lX.%lu: Good subkey binding\n"), + (ulong)keyid_from_pk(pk,NULL), lid ); + keyflags |= KEYF_CHECKED | KEYF_VALID; } else { - log_error(_("sig record %lu[%d] points to wrong record.\n"), - rec.r.sig.sig[i].lid, i ); - tdbio_invalid(); + log_info(_( + "key %08lX.%lu: Invalid subkey binding: %s\n"), + (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); + keyflags |= KEYF_CHECKED; + keyflags &= ~KEYF_VALID; + } + keybind_seen = 1; + } + else if( sig->sig_class == 0x20 && !revoke_seen ) { + /* this is a key revocation certificate: check it */ + rc = check_key_signature( keyblock, node, NULL ); + if( !rc ) { + if( opt.verbose ) + log_info(_("key %08lX.%lu: Valid key revocation\n"), + (ulong)keyid_from_pk(pk, NULL), lid ); + keyflags |= KEYF_REVOKED; /* fixme: revoke the main key too*/ + } + else { + log_info(_( + "key %08lX.%lu: Invalid key revocation: %s\n"), + (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); + } + revoke_seen = 1; + } + else if( sig->sig_class == 0x28 && !revoke_seen && !is_main ) { + /* this is a subkey revocation certificate: check it */ + /* fixme: we should also check that the revocation + * is newer than the key (OpenPGP) */ + rc = check_key_signature( keyblock, node, NULL ); + if( !rc ) { + if( opt.verbose ) + log_info(_( + "key %08lX.%lu: Valid subkey revocation\n"), + (ulong)keyid_from_pk(pk,NULL), lid ); + keyflags |= KEYF_REVOKED; + } + else { + log_info(_( + "key %08lX.%lu: Invalid subkey binding: %s\n"), + (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); + } + revoke_seen = 1; + } + /* Hmmm: should we handle direct key signatures here? */ + } + + return keyflags; +} + + +static ulong +make_key_records( KBNODE keyblock, ulong lid, u32 *keyid ) +{ + TRUSTREC *krecs, **kend, *k, *k2; + KBNODE node; + PKT_public_key *pk; + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; + ulong keyrecno; + + krecs = NULL; kend = &krecs; + for( node=keyblock; node; node = node->next ) { + if( node->pkt->pkttype != PKT_PUBLIC_KEY + && node->pkt->pkttype != PKT_PUBLIC_SUBKEY ) + continue; + pk = node->pkt->pkt.public_key; + fingerprint_from_pk( pk, fpr, &fprlen ); + + /* create the key record */ + k = m_alloc_clear( sizeof *k ); + k->rectype = RECTYPE_KEY; + k->r.key.lid = lid; + k->r.key.pubkey_algo = pk->pubkey_algo; + k->r.key.fingerprint_len = fprlen; + memcpy(k->r.key.fingerprint, fpr, fprlen ); + k->recnum = tdbio_new_recnum(); + *kend = k; + kend = &k->next; + + k->r.key.keyflags = check_keybinding( keyblock, node, keyid, lid, pk ); + + } + + keyrecno = krecs? krecs->recnum : 0; + /* write the keylist and release the memory */ + for( k = krecs; k ; k = k2 ) { + if( k->next ) + k->r.key.next = k->next->recnum; + write_record( k ); + k2 = k->next; + m_free( k ); + } + return keyrecno; +} + + +/**************** + * Check the validity of a user ID and calculate the uidflags + * keynode points to + * a node with a user ID. mainkid has the key ID of the primary key + * keyblock is the complete keyblock which is needed for signature + * checking. + */ +static unsigned int +check_uidsigs( KBNODE keyblock, KBNODE keynode, u32 *mainkid, ulong lid ) +{ + KBNODE node; + unsigned int uidflags = 0; + PKT_signature *sig; + PKT_signature *selfsig = NULL; /* the latest valid self signature */ + int rc; + + /* first we check only the selfsignatures */ + for( node=keynode->next; node; node = node->next ) { + if( node->pkt->pkttype == PKT_USER_ID + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + break; /* ready */ + if( node->pkt->pkttype != PKT_SIGNATURE ) + continue; /* don't care about other packets */ + sig = node->pkt->pkt.signature; + if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] ) + continue; /* we only care about self-signatures for now */ + + if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */ + rc = check_key_signature( keyblock, node, NULL ); + if( !rc ) { + if( opt.verbose ) + log_info( "uid %08lX.%lu: %s\n", + (ulong)mainkid[1], lid, _("Good self-signature") ); + uidflags |= UIDF_CHECKED | UIDF_VALID; + if( !selfsig ) + selfsig = sig; /* use the first valid sig */ + else if( sig->timestamp > selfsig->timestamp + && sig->sig_class >= selfsig->sig_class ) + selfsig = sig; /* but this one is newer */ + } + else { + log_info( "uid %08lX: %s: %s\n", + (ulong)mainkid[1], _("Invalid self-signature"), + g10_errstr(rc) ); + uidflags |= UIDF_CHECKED; } } - 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; + } + + /* and now check for revocations - we must do this after the + * self signature check because a self-signature which is newer + * than a revocation makes the revocation invalid. + * Fixme: Is this correct - check with rfc2440 */ + for( node=keynode->next; node; node = node->next ) { + if( node->pkt->pkttype == PKT_USER_ID + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + break; /* ready */ + if( node->pkt->pkttype != PKT_SIGNATURE ) + continue; /* don't care about other packets */ + sig = node->pkt->pkt.signature; + if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] ) + continue; /* we only care about self-signatures for now */ + + if( sig->sig_class == 0x30 ) { /* cert revocation */ + rc = check_key_signature( keyblock, node, NULL ); + if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) { + log_info( "uid %08lX.%lu: %s\n", + (ulong)mainkid[1], lid, + _("Valid user ID revocation skipped " + "due to a newer self signature") ); + } + else if( !rc ) { + if( opt.verbose ) + log_info( "uid %08lX.%lu: %s\n", + (ulong)mainkid[1], lid, _("Valid user ID revocation") ); + uidflags |= UIDF_CHECKED | UIDF_VALID | UIDF_REVOKED; + } + else { + log_info("uid %08lX: %s: %s\n", + (ulong)mainkid[1], _("Invalid user ID revocation"), + g10_errstr(rc) ); + } } } - 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. */ + return uidflags; +} - if( !pk_lid ) /* we have already seen that there is no pubkey */ - rc = G10ERR_NO_PUBKEY; + +static unsigned int +check_sig_record( KBNODE keyblock, KBNODE signode, + ulong siglid, int sigidx, u32 *keyid, ulong lid ) +{ + PKT_signature *sig = signode->pkt->pkt.signature; + unsigned int sigflag = 0; + TRUSTREC tmp; + int revocation=0, rc; + + if( (sig->sig_class&~3) == 0x10 ) /* regular certification */ + ; + else if( sig->sig_class == 0x30 ) /* cert revocation */ + revocation = 1; else - rc = check_key_signature( keyblock, signode, NULL ); + return SIGF_CHECKED | SIGF_IGNORED; - if( !rc ) { /* valid signature */ - if( opt.verbose ) - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1], - revoked? _("Valid certificate revocation") - : _("Good certificate") ); - newlid = pk_lid; /* this is the pk of the signature */ - newflag = SIGF_CHECKED | SIGF_VALID; - if( revoked ) { - newflag |= SIGF_REVOKED; - *mod_down = 1; + read_record( siglid, &tmp, 0 ); + if( tmp.rectype == RECTYPE_DIR ) { + /* the public key is in the trustdb: check sig */ + rc = check_key_signature( keyblock, signode, NULL ); + if( !rc ) { /* valid signature */ + if( opt.verbose ) + log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s\n", + (ulong)keyid[1], lid, siglid, sigidx, + (ulong)sig->keyid[1], + revocation? _("Valid certificate revocation") + : _("Good certificate") ); + sigflag |= SIGF_CHECKED | SIGF_VALID; + if( revocation ) { + sigflag |= SIGF_REVOKED; + /**mod_down = 1;*/ + } + else + /**mod_up = 1*/; + } + else if( rc == G10ERR_NO_PUBKEY ) { + /* This may happen if the key is still in the trustdb + * but not available in the keystorage */ + sigflag |= SIGF_NOPUBKEY; + /**mod_down = 1;*/ + if( revocation ) + sigflag |= SIGF_REVOKED; + } + else { + log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s: %s\n", + (ulong)keyid[1], lid, siglid, sigidx, + (ulong)sig->keyid[1], + revocation? _("Invalid certificate revocation") + : _("Invalid certificate"), + g10_errstr(rc)); + sigflag |= SIGF_CHECKED; + if( revocation ) { + sigflag |= SIGF_REVOKED; + /**mod_down = 1;*/ + } } - else - *mod_up = 1; } - else if( rc == G10ERR_NO_PUBKEY ) { - if( opt.verbose > 1 || DBG_TRUST ) - log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n", - (ulong)keyid[1], lid, uidhash[18], - uidhash[19], (ulong)sig->keyid[1], g10_errstr(rc) ); - newlid = create_shadow_dir( sig, lid ); - newflag = SIGF_NOPUBKEY; - if( revoked ) - newflag |= SIGF_REVOKED; + else if( tmp.rectype == RECTYPE_SDIR ) { + /* better 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 )) + sigflag |= SIGF_NOPUBKEY; + else + log_error(_("sig record %lu[%d] points to wrong record.\n"), + siglid, sigidx ); } else { - log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n", - (ulong)keyid[1], lid, uidhash[18], uidhash[19], - (ulong)sig->keyid[1], - revoked? _("Invalid certificate revocation") - : _("Invalid certificate"), - g10_errstr(rc)); - newlid = create_shadow_dir( sig, lid ); - newflag = SIGF_CHECKED; - if( revoked ) - newflag |= SIGF_REVOKED; - *mod_down = 1; + log_error(_("sig record %lu[%d] points to wrong record.\n"), + siglid, sigidx ); + tdbio_invalid(); } - if( delrec.recnum ) { /* we can reuse an unused slot */ - delrec.r.sig.sig[delrecidx].lid = newlid; - delrec.r.sig.sig[delrecidx].flag= newflag; - write_record( &delrec ); - } - else { /* we must insert a new sig record */ - TRUSTREC tmp; - - memset( &tmp, 0, sizeof tmp ); - tmp.recnum = tdbio_new_recnum(); - tmp.rectype = RECTYPE_SIG; - tmp.r.sig.lid = lid; - tmp.r.sig.next = urec->r.uid.siglist; - tmp.r.sig.sig[0].lid = newlid; - tmp.r.sig.sig[0].flag= newflag; - write_record( &tmp ); - urec->r.uid.siglist = tmp.recnum; - urec->dirty = 1; - } + return sigflag; } +/**************** + * Make the sig records for the given uid record + * We don't set flags here or even check the signatures; this will + * happen latter. + */ +static ulong +make_sig_records( KBNODE keyblock, KBNODE uidnode, ulong lid, u32 *mainkid ) +{ + TRUSTREC *srecs, **s_end, *s=NULL, *s2; + KBNODE node; + PKT_signature *sig; + ulong sigrecno, siglid; + int i, sigidx = 0; + + srecs = NULL; s_end = &srecs; + for( node=uidnode->next; node; node = node->next ) { + if( node->pkt->pkttype == PKT_USER_ID + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + break; /* ready */ + if( node->pkt->pkttype != PKT_SIGNATURE ) + continue; /* don't care about other packets */ + sig = node->pkt->pkt.signature; + if( mainkid[0] == sig->keyid[0] && mainkid[1] == sig->keyid[1] ) + continue; /* we don't care about self-signatures here */ + + siglid = find_or_create_lid( sig ); + /* smash dups */ + for( s2 = s; s2 ; s2 = s2->next ) { + for(i=0; i < sigidx; i++ ) { + if( s2->r.sig.sig[i].lid == siglid ) + goto leaveduptest; + } + } + for( s2 = srecs; s2 ; s2 = s2->next ) { + for(i=0; i < SIGS_PER_RECORD; i++ ) { + if( s2->r.sig.sig[i].lid == siglid ) + goto leaveduptest; + } + } + leaveduptest: + if( s2 ) { + log_info( "sig %08lX.%lu: %s\n", (ulong)mainkid[1], lid, + _("duplicated certificate - deleted") ); + continue; + } + + /* create the sig record */ + if( !sigidx ) { + s = m_alloc_clear( sizeof *s ); + s->rectype = RECTYPE_SIG; + s->r.sig.lid = lid; + } + s->r.sig.sig[sigidx].lid = siglid; + s->r.sig.sig[sigidx].flag= check_sig_record( keyblock, node, + siglid, sigidx, + mainkid, lid ); + sigidx++; + if( sigidx == SIGS_PER_RECORD ) { + s->recnum = tdbio_new_recnum(); + *s_end = s; + s_end = &s->next; + sigidx = 0; + } + } + if( sigidx ) { + s->recnum = tdbio_new_recnum(); + *s_end = s; + s_end = &s->next; + } + + sigrecno = srecs? srecs->recnum : 0; + /* write the keylist and release the memory */ + for( s = srecs; s ; s = s2 ) { + if( s->next ) + s->r.sig.next = s->next->recnum; + write_record( s ); + s2 = s->next; + m_free( s ); + } + return sigrecno; +} + + +static ulong +make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid ) +{ + TRUSTREC *urecs, **uend, *u, *u2; + KBNODE node; + PKT_user_id *uid; + byte uidhash[20]; + ulong uidrecno; + + urecs = NULL; uend = &urecs; + for( node=keyblock; node; node = node->next ) { + if( node->pkt->pkttype != PKT_USER_ID ) + continue; + uid = node->pkt->pkt.user_id; + rmd160_hash_buffer( uidhash, uid->name, uid->len ); + + /* create the uid record */ + u = m_alloc_clear( sizeof *u ); + u->rectype = RECTYPE_UID; + u->r.uid.lid = lid; + memcpy(u->r.uid.namehash, uidhash, 20 ); + u->recnum = tdbio_new_recnum(); + *uend = u; + uend = &u->next; + + u->r.uid.uidflags = check_uidsigs( keyblock, node, keyid, lid ); + if( (u->r.uid.uidflags & UIDF_CHECKED) + && (u->r.uid.uidflags & UIDF_VALID) ) + /*make_pref_record( &urec, keyid, selfsig )*/; + /* create the list of signatures */ + u->r.uid.siglist = make_sig_records( keyblock, node, lid, keyid ); + } + + uidrecno = urecs? urecs->recnum : 0; + /* write the uidlist and release the memory */ + for( u = urecs; u ; u = u2 ) { + if( u->next ) + u->r.uid.next = u->next->recnum; + write_record( u ); + u2 = u->next; + m_free( u ); + } + return uidrecno; +} + + /**************** * Update all the info from the public keyblock. * The key must already exist in the keydb. - * This function is responsible for checking the signatures in cases - * where the public key is already available. If we do not have the public - * key, the check is done by some special code in insert_trust_record(). */ int update_trust_record( KBNODE keyblock, int recheck, int *modified ) { PKT_public_key *primary_pk; KBNODE node; - TRUSTREC drec; - TRUSTREC krec; - TRUSTREC urec; - TRUSTREC prec; - TRUSTREC helprec; + TRUSTREC drec, krec, urec, prec, helprec; int rc = 0; u32 keyid[2]; /* keyid of primary key */ - ulong recno, lastrecno; int mod_up = 0; int mod_down = 0; - RECNO_LIST recno_list = NULL; /* list of verified records */ - /* fixme: replace recno_list by a lookup on node->recno */ + ulong recno, r2; if( opt.dry_run ) return 0; @@ -1862,89 +1448,47 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified ) keyid_from_pk( primary_pk, keyid ); - /* fixme: check that the keyblock has a valid structure */ - rc = tdbio_begin_transaction(); if( rc ) return rc; - /* update the keys */ - for( node=keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - upd_key_record( keyblock, node, keyid, - &drec, &recno_list, recheck ); - } - /* update the user IDs */ - for( node=keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) - upd_uid_record( keyblock, node, keyid, - &drec, &recno_list, recheck, &mod_up, &mod_down ); - } - - /* delete keyrecords from the trustdb which are not anymore used */ - /* should we really do this, or is it better to keep them and */ - /* mark as unused? */ - /* And set the revocation flag into the dir record */ - drec.r.dir.dirflags &= ~DIRF_REVOKED; - lastrecno = 0; + /* delete the old stuff */ for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) { read_record( recno, &krec, RECTYPE_KEY ); - if( recno == drec.r.dir.keylist ) { /* this is the primary key */ - if( (krec.r.key.keyflags & KEYF_REVOKED) ) { - drec.r.dir.dirflags |= DIRF_REVOKED; - drec.dirty = 1; - } - } - - if( !qry_recno_list( recno_list, recno, RECTYPE_KEY ) ) { - /* delete this one */ - if( !lastrecno ) { - drec.r.dir.keylist = krec.r.key.next; - drec.dirty = 1; - } - else { - read_record( lastrecno, &helprec, RECTYPE_KEY ); - helprec.r.key.next = krec.r.key.next; - write_record( &helprec ); - } - delete_record( recno ); - } - else - lastrecno = recno; + delete_record( recno ); } - /* delete uid records and sig and their pref records from the - * trustdb which are not anymore used */ - lastrecno = 0; + drec.r.dir.keylist = 0; for( recno=drec.r.dir.uidlist; recno; recno = urec.r.uid.next ) { read_record( recno, &urec, RECTYPE_UID ); - if( !qry_recno_list( recno_list, recno, RECTYPE_UID ) ) { - ulong r2; - /* delete this one */ - if( !lastrecno ) { - drec.r.dir.uidlist = urec.r.uid.next; - drec.dirty = 1; - } - else { - read_record( lastrecno, &helprec, RECTYPE_UID ); - helprec.r.uid.next = urec.r.uid.next; - write_record( &helprec ); - } - for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) { - read_record( r2, &prec, RECTYPE_PREF ); - delete_record( r2 ); - } - for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) { - read_record( r2, &helprec, RECTYPE_SIG ); - delete_record( r2 ); - } - delete_record( recno ); + for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) { + read_record( r2, &prec, RECTYPE_PREF ); + delete_record( r2 ); } - else - lastrecno = recno; + for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) { + read_record( r2, &helprec, RECTYPE_SIG ); + delete_record( r2 ); + } + delete_record( recno ); } + drec.r.dir.uidlist = 0; + /* insert new stuff */ + drec.r.dir.dirflags &= ~DIRF_REVOKED; + drec.r.dir.keylist = make_key_records( keyblock, drec.recnum, keyid ); + drec.r.dir.uidlist = make_uid_records( keyblock, drec.recnum, keyid ); + #if 0 + if( orig_uidflags != urec.r.uid.uidflags ) { + write_record( &urec ); + if( !( urec.r.uid.uidflags & UIDF_VALID ) + || ( urec.r.uid.uidflags & UIDF_REVOKED ) ) + *mod_down=1; + else + *mod_up=1; /*(maybe a new user id)*/ + #endif + + /* FIXME: if the primary key has been revoked, we should + set the revoked flag in the dir records */ if( rc ) rc = tdbio_cancel_transaction(); @@ -1953,15 +1497,16 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified ) *modified = 1; drec.r.dir.dirflags |= DIRF_CHECKED; drec.r.dir.valcheck = 0; + drec.r.dir.checkat = make_timestamp(); write_record( &drec ); - tdbio_write_modify_stamp( mod_up, mod_down ); + /*tdbio_write_modify_stamp( mod_up, mod_down );*/ rc = tdbio_end_transaction(); } - rel_recno_list( &recno_list ); return rc; } + /**************** * Insert a trust record into the TrustDB * This function assumes that the record does not yet exist. @@ -1976,7 +1521,6 @@ insert_trust_record( PKT_public_key *orig_pk ) byte fingerprint[MAX_FINGERPRINT_LEN]; size_t fingerlen; int rc = 0; - ulong hintlist = 0; PKT_public_key *pk; @@ -2022,9 +1566,7 @@ insert_trust_record( PKT_public_key *orig_pk ) } /* We have to look for a shadow dir record which must be reused - * as the dir record. And: check all signatures which are listed - * in the hintlist of the shadow dir record. - */ + * as the dir record. */ rc = tdbio_search_sdir( pk->keyid, pk->pubkey_algo, &shadow ); if( rc && rc != -1 ) { log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc)); @@ -2032,19 +1574,14 @@ insert_trust_record( PKT_public_key *orig_pk ) } memset( &dirrec, 0, sizeof dirrec ); dirrec.rectype = RECTYPE_DIR; - if( !rc ) { - /* hey, great: this key has already signed other keys - * convert this to a real directory entry */ - hintlist = shadow.r.sdir.hintlist; + if( !rc ) /* we have a shadow dir record - convert to dir record */ dirrec.recnum = shadow.recnum; - } - else { + else dirrec.recnum = tdbio_new_recnum(); - } dirrec.r.dir.lid = dirrec.recnum; write_record( &dirrec ); - /* out the LID into the keyblock */ + /* put the LID into the in-memory copy of the keyblock */ pk->local_id = dirrec.r.dir.lid; orig_pk->local_id = dirrec.r.dir.lid; for( node=keyblock; node; node = node->next ) { @@ -2064,18 +1601,137 @@ insert_trust_record( PKT_public_key *orig_pk ) /* and put all the other stuff into the keydb */ rc = update_trust_record( keyblock, 1, NULL ); - if( !rc ) - process_hintlist( hintlist, dirrec.r.dir.lid ); leave: - if( rc && hintlist ) - ; /* fixme: the hintlist is not anymore anchored */ release_kbnode( keyblock ); do_sync(); return rc; } +/**************** + * Walk over the keyrings and create trustdb records for all keys + * It is intended to be used after a fast-import operation. + */ +void +update_trustdb() +{ + KBNODE keyblock = NULL; + KBPOS kbpos; + int rc; + + if( opt.dry_run ) + return; + + init_trustdb(); + rc = enum_keyblocks( 0, &kbpos, &keyblock ); + if( !rc ) { + ulong count=0, upd_count=0, err_count=0, new_count=0; + + while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) { + int modified; + + rc = update_trust_record( keyblock, 1, &modified ); + if( rc == -1 ) { /* not yet in trustdb: insert */ + PKT_public_key *pk = keyblock->pkt->pkt.public_key; + rc = insert_trust_record( pk ); + if( rc && !pk->local_id ) { + log_error(_("lid ?: insert failed: %s\n"), + g10_errstr(rc) ); + err_count++; + } + else if( rc ) { + log_error(_("lid %lu: insert failed: %s\n"), + pk->local_id, g10_errstr(rc) ); + err_count++; + } + else { + if( opt.verbose ) + log_info(_("lid %lu: inserted\n"), pk->local_id ); + new_count++; + } + } + else if( rc ) { + log_error(_("lid %lu: update failed: %s\n"), + lid_from_keyblock(keyblock), g10_errstr(rc) ); + err_count++; + } + else if( modified ) { + if( opt.verbose ) + log_info(_("lid %lu: updated\n"), + lid_from_keyblock(keyblock)); + upd_count++; + } + else if( opt.verbose > 1 ) + log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) ); + + release_kbnode( keyblock ); keyblock = NULL; + if( !(++count % 100) ) + log_info(_("%lu keys so far processed\n"), count); + } + log_info(_("%lu keys processed\n"), count); + if( err_count ) + log_info(_("\t%lu keys with errors\n"), err_count); + if( upd_count ) + log_info(_("\t%lu keys updated\n"), upd_count); + if( new_count ) + log_info(_("\t%lu keys inserted\n"), new_count); + } + if( rc && rc != -1 ) + log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc)); + + enum_keyblocks( 2, &kbpos, &keyblock ); /* close */ + release_kbnode( keyblock ); +} + + + +/**************** + * Do all required check in the trustdb. This function walks over all + * records in the trustdb and does scheduled processing. + */ +void +check_trustdb( const char *username ) +{ + TRUSTREC rec; + ulong recnum; + ulong count=0, upd_count=0, err_count=0, skip_count=0; + ulong current_time = make_timestamp(); + + if( username ) + log_info("given user IDs ignored in check_trustdb\n"); + + init_trustdb(); + + for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) { + if( rec.rectype != RECTYPE_DIR ) + continue; /* we only want the dir records */ + + if( count && !(count % 100) && !opt.quiet ) + log_info(_("%lu keys so far processed\n"), count); + count++; + if( !rec.r.dir.checkat || rec.r.dir.checkat > current_time ) { + skip_count++; + continue; /* not scheduled for checking */ + } + + if( !rec.r.dir.keylist ) { + log_info(_("lid %lu: dir record w/o key - skipped\n"), recnum); + skip_count++; + continue; + } + + } + + 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); +} + /*********************************************** @@ -2499,184 +2155,6 @@ clear_trust_checked_flag( PKT_public_key *pk ) } -/**************** - * Put new entries from the pubrings into the trustdb. - * This function honors the sig flags to speed up the check. - */ -void -update_trustdb( ) -{ - KBNODE keyblock = NULL; - KBPOS kbpos; - int rc; - - if( opt.dry_run ) - return; - - init_trustdb(); - rc = enum_keyblocks( 0, &kbpos, &keyblock ); - if( !rc ) { - ulong count=0, upd_count=0, err_count=0, new_count=0; - - while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) { - int modified; - - rc = update_trust_record( keyblock, 1, &modified ); - if( rc == -1 ) { /* not yet in trustdb: insert */ - PKT_public_key *pk = keyblock->pkt->pkt.public_key; - rc = insert_trust_record( pk ); - if( rc && !pk->local_id ) { - log_error(_("lid ?: insert failed: %s\n"), - g10_errstr(rc) ); - err_count++; - } - else if( rc ) { - log_error(_("lid %lu: insert failed: %s\n"), - pk->local_id, g10_errstr(rc) ); - err_count++; - } - else { - if( opt.verbose ) - log_info(_("lid %lu: inserted\n"), pk->local_id ); - new_count++; - } - } - else if( rc ) { - log_error(_("lid %lu: update failed: %s\n"), - lid_from_keyblock(keyblock), g10_errstr(rc) ); - err_count++; - } - else if( modified ) { - if( opt.verbose ) - log_info(_("lid %lu: updated\n"), - lid_from_keyblock(keyblock)); - upd_count++; - } - else if( opt.verbose > 1 ) - log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) ); - - release_kbnode( keyblock ); keyblock = NULL; - if( !(++count % 100) ) - log_info(_("%lu keys so far processed\n"), count); - } - log_info(_("%lu keys processed\n"), count); - if( err_count ) - log_info(_("\t%lu keys with errors\n"), err_count); - if( upd_count ) - log_info(_("\t%lu keys updated\n"), upd_count); - if( new_count ) - log_info(_("\t%lu keys inserted\n"), new_count); - } - if( rc && rc != -1 ) - log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc)); - - enum_keyblocks( 2, &kbpos, &keyblock ); /* close */ - release_kbnode( keyblock ); -} - -/**************** - * Check the complete trustdb or only the entries for the given username. - * We check the complete database. If a username is given or the special - * username "*" is used, a complete recheck is done. With no user ID - * only the records which are not yet checkd are now checked. - */ -void -check_trustdb( const char *username ) -{ - TRUSTREC rec; - KBNODE keyblock = NULL; - KBPOS kbpos; - int rc; - int recheck = username && *username == '*' && !username[1]; - - init_trustdb(); - if( username && !recheck ) { - rc = find_keyblock_byname( &kbpos, username ); - if( !rc ) - rc = read_keyblock( &kbpos, &keyblock ); - if( rc ) { - log_error(_("%s: keyblock read problem: %s\n"), - username, g10_errstr(rc)); - } - else { - int modified; - - rc = update_trust_record( keyblock, 1, &modified ); - if( rc == -1 ) { /* not yet in trustdb: insert */ - rc = insert_trust_record( - find_kbnode( keyblock, PKT_PUBLIC_KEY - ) ->pkt->pkt.public_key ); - - } - if( rc ) - log_error(_("%s: update failed: %s\n"), - username, g10_errstr(rc) ); - else if( modified ) - log_info(_("%s: updated\n"), username ); - else - log_info(_("%s: okay\n"), username ); - - } - release_kbnode( keyblock ); keyblock = NULL; - } - else { - ulong recnum; - ulong count=0, upd_count=0, err_count=0, skip_count=0; - - for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) { - if( rec.rectype == RECTYPE_DIR ) { - TRUSTREC tmp; - int modified; - - if( !rec.r.dir.keylist ) { - log_info(_("lid %lu: dir record w/o key - skipped\n"), - recnum); - count++; - skip_count++; - continue; - } - - read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY ); - - rc = get_keyblock_byfprint( &keyblock, - tmp.r.key.fingerprint, - tmp.r.key.fingerprint_len ); - if( rc ) { - log_error(_("lid %lu: keyblock not found: %s\n"), - recnum, g10_errstr(rc) ); - count++; - skip_count++; - continue; - } - - rc = update_trust_record( keyblock, recheck, &modified ); - if( rc ) { - log_error(_("lid %lu: update failed: %s\n"), - recnum, g10_errstr(rc) ); - err_count++; - } - else if( modified ) { - if( opt.verbose ) - log_info(_("lid %lu: updated\n"), recnum ); - upd_count++; - } - else if( opt.verbose > 1 ) - log_info(_("lid %lu: okay\n"), recnum ); - - release_kbnode( keyblock ); keyblock = NULL; - if( !(++count % 100) ) - log_info(_("%lu keys so far processed\n"), count); - } - } - log_info(_("%lu keys processed\n"), count); - if( skip_count ) - log_info(_("\t%lu keys skipped\n"), skip_count); - if( err_count ) - log_info(_("\t%lu keys with errors\n"), err_count); - if( upd_count ) - log_info(_("\t%lu keys updated\n"), upd_count); - } -} @@ -2828,6 +2306,8 @@ query_trust_info( PKT_public_key *pk, const byte *namehash ) init_trustdb(); if( check_trust( pk, &trustlevel, namehash, NULL, NULL ) ) return '?'; + if( trustlevel & TRUST_FLAG_DISABLED ) + return 'd'; if( trustlevel & TRUST_FLAG_REVOKED ) return 'r'; c = trust_letter( (trustlevel & TRUST_MASK) ); diff --git a/g10/trustdb.h b/g10/trustdb.h index 777c4749d..9f3e4c35f 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -34,6 +34,7 @@ /* trust values not covered by the mask */ #define TRUST_FLAG_REVOKED 32 /* r: revoked */ #define TRUST_FLAG_SUB_REVOKED 64 +#define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */ #define PREFTYPE_SYM 1 diff --git a/include/ChangeLog b/include/ChangeLog index 5f4cb82b0..a1f94e32a 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +Tue Jun 29 21:44:25 CEST 1999 Werner Koch + + + * util.h (stricmp): Use strcasecmp as replacement. + Sat Jun 26 12:15:59 CEST 1999 Werner Koch diff --git a/include/util.h b/include/util.h index 9a4f1ffb5..d266af412 100644 --- a/include/util.h +++ b/include/util.h @@ -175,8 +175,6 @@ char *native_to_utf8( const char *string ); char *utf8_to_native( const char *string ); int check_utf8_string( const char *string ); -#define stricmp(a,b) strcasecmp((a),(b)) - #ifndef HAVE_MEMICMP int memicmp( const char *a, const char *b, size_t n ); #endif @@ -192,7 +190,9 @@ char *strlwr(char *a); #ifndef HAVE_MEMMOVE #define memmove(d, s, n) bcopy((s), (d), (n)) #endif - +#ifndef HAVE_STRICMP + #define stricmp(a,b) strcasecmp( (a), (b) ) +#endif /**** other missing stuff ****/ #ifndef HAVE_ATEXIT /* For SunOS */ diff --git a/mpi/mpi-mul.c b/mpi/mpi-mul.c index df8eb2586..f83824926 100644 --- a/mpi/mpi-mul.c +++ b/mpi/mpi-mul.c @@ -189,6 +189,7 @@ mpi_mul( MPI w, MPI u, MPI v) } + void mpi_mulm( MPI w, MPI u, MPI v, MPI m) { diff --git a/po/ChangeLog b/po/ChangeLog index 9d8490e21..2a41f4bb7 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,6 +1,10 @@ -Sat Jun 26 12:15:59 CEST 1999 Werner Koch +Tue Jun 29 21:44:25 CEST 1999 Werner Koch + * it.po: Updated (Marco). + +Sat Jun 26 12:15:59 CEST 1999 Werner Koch + * pt_BR.po: Updated (Thiago). Thu Jun 10 14:18:23 CEST 1999 Werner Koch diff --git a/po/it.po b/po/it.po index 441036a66..965a84fbe 100644 --- a/po/it.po +++ b/po/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg-0.9.7\n" "POT-Creation-Date: 1999-06-26 11:22+0200\n" -"PO-Revision-Date: 1999-05-15 18:09+02:00\n" +"PO-Revision-Date: 1999-06-28 19:49+02:00\n" "Last-Translator: Marco d'Itri \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" @@ -38,9 +38,8 @@ msgid "quit" msgstr "quit" #: util/miscutil.c:176 -#, fuzzy msgid "qQ" -msgstr "q" +msgstr "qQ" #: util/errors.c:54 msgid "general error" @@ -448,7 +447,7 @@ msgstr "meno prolisso" #: g10/g10.c:234 msgid "don't use the terminal at all" -msgstr "" +msgstr "non usa per niente il terminale" #: g10/g10.c:235 msgid "force v3 signatures" @@ -533,7 +532,7 @@ msgstr "emula il modo descritto in RFC 1991" #: g10/g10.c:258 msgid "set all packet, cipher and digest options to OpenPGP behavior" -msgstr "" +msgstr "imposta per OpenPGP le opzioni di pacchetto, cifrario e digest" #: g10/g10.c:259 msgid "|N|use passphrase mode N" @@ -565,7 +564,7 @@ msgstr "elimina il campo keyid dei pacchetti cifrati" #: g10/g10.c:268 msgid "|NAME=VALUE|use this notation data" -msgstr "" +msgstr "|NOME=VALORE|usa questi dati per una nota" #: g10/g10.c:270 msgid "" @@ -651,7 +650,7 @@ msgstr "l'algoritmo di digest selezionato non #: g10/g10.c:849 msgid "the given policy URL is invalid\n" -msgstr "" +msgstr "L'URL della policy indicato non è valido\n" #: g10/g10.c:852 #, c-format @@ -764,20 +763,24 @@ msgstr "impossibile aprire `%s'\n" msgid "" "the first character of a notation name must be a letter or an underscore\n" msgstr "" +"il primo carattere del nome di una nota deve essere una lettera o un\n" +"underscore\n" #: g10/g10.c:1463 msgid "" "a notation name must have only letters, digits, dots or underscores and end " "with an '='\n" msgstr "" +"il nome di una nota deve essere formato solo da lettere, numeri, punti o\n" +"underscore e deve finire con `='\n" #: g10/g10.c:1469 msgid "dots in a notation name must be surrounded by other characters\n" -msgstr "" +msgstr "nel nome di una nota i punti devono avere altri caratteri intorno\n" #: g10/g10.c:1477 msgid "a notation value must not use any control characters\n" -msgstr "" +msgstr "il valore di una nota non deve usare caratteri di controllo\n" #: g10/armor.c:296 #, c-format @@ -1052,9 +1055,9 @@ msgid "%s: skipped: %s\n" msgstr "%s: saltata: %s\n" #: g10/pkclist.c:588 g10/pkclist.c:687 -#, fuzzy, c-format +#, c-format msgid "%s: skipped: public key already present\n" -msgstr "%s: il keyblock ha problemi di lettura: %s\n" +msgstr "%s: saltato: chiave pubblica già presente\n" #: g10/pkclist.c:611 msgid "" @@ -1356,7 +1359,6 @@ msgid "DSA keypair will have 1024 bits.\n" msgstr "La coppia DSA avrà 1024 bit.\n" #: g10/keygen.c:859 -#, fuzzy msgid "Key generation canceled.\n" msgstr "Generazione della chiave annullata.\n" @@ -1467,7 +1469,7 @@ msgid "using secondary key %08lX instead of primary key %08lX\n" msgstr "uso la chiave secondaria %08lX invece della chiave primaria %08lX\n" #: g10/import.c:116 -#, fuzzy, c-format +#, c-format msgid "can't open `%s': %s\n" msgstr "impossibile aprire `%s': %s\n" @@ -1482,9 +1484,9 @@ msgid "%lu keys so far processed\n" msgstr "Per ora sono state esaminate %lu chiavi\n" #: g10/import.c:172 -#, fuzzy, c-format +#, c-format msgid "error reading `%s': %s\n" -msgstr "errore nella creazione della passhprase: %s\n" +msgstr "errore leggendo `%s': %s\n" #: g10/import.c:175 #, c-format @@ -1570,14 +1572,14 @@ msgid "writing to `%s'\n" msgstr "scrittura in `%s'\n" #: g10/import.c:379 g10/import.c:435 g10/import.c:544 g10/import.c:645 -#, fuzzy, c-format +#, c-format msgid "can't lock keyring `%s': %s\n" -msgstr "impossibile bloccare il portachiavi pubblico: %s\n" +msgstr "impossibile fare il lock del portachiavi `%s': %s\n" #: g10/import.c:382 g10/import.c:438 g10/import.c:547 g10/import.c:648 -#, fuzzy, c-format +#, c-format msgid "error writing keyring `%s': %s\n" -msgstr "%s: errore durante la scrittura del record di versione: %s\n" +msgstr "errore scrivendo il portachiavi `%s': %s\n" #: g10/import.c:387 #, c-format @@ -1724,7 +1726,7 @@ msgstr "chiave %08lX: certificato di revoca non valido: %s - saltato\n" #: g10/import.c:915 #, c-format msgid "key %08lX: duplicated user ID detected - merged\n" -msgstr "" +msgstr "chiave %08lX: trovato un user ID duplicato - unito\n" #: g10/import.c:966 #, c-format @@ -1988,14 +1990,12 @@ msgid "delete a secondary key" msgstr "cancella una chiave secondaria" #: g10/keyedit.c:579 -#, fuzzy msgid "delsig" -msgstr "lsign" +msgstr "delsign" #: g10/keyedit.c:579 -#, fuzzy msgid "delete signatures" -msgstr "elenca le firme" +msgstr "cancella le firme" #: g10/keyedit.c:580 msgid "expire" @@ -2152,35 +2152,33 @@ msgstr "Comando non valido (prova \"help\")\n" #: g10/keyedit.c:1294 msgid "Delete this good signature? (y/N/q)" -msgstr "" +msgstr "Cancellare questa firma corretta? (s/N/q)" #: g10/keyedit.c:1298 msgid "Delete this invalid signature? (y/N/q)" -msgstr "" +msgstr "Cancellare questa firma non valida? (s/N/q)" #: g10/keyedit.c:1302 msgid "Delete this unknown signature? (y/N/q)" -msgstr "" +msgstr "Cancellare questa firma sconosciuta? (s/N/q)" #: g10/keyedit.c:1308 -#, fuzzy msgid "Really delete this self-signature? (y/N)" -msgstr "Creare davvero i certificati di revoca? (s/N)" +msgstr "Cancellare davvero questa autofirma? (s/N)" #: g10/keyedit.c:1322 -#, fuzzy, c-format +#, c-format msgid "Deleted %d signature.\n" -msgstr "%d firme non corrette\n" +msgstr "Cancellata %d firma.\n" #: g10/keyedit.c:1323 -#, fuzzy, c-format +#, c-format msgid "Deleted %d signatures.\n" -msgstr "%d firme non corrette\n" +msgstr "Cancellate %d firme.\n" #: g10/keyedit.c:1326 -#, fuzzy msgid "Nothing deleted.\n" -msgstr "ATTENZIONE: non è stato esportato nulla\n" +msgstr "Non è stato cancellato nulla.\n" #: g10/keyedit.c:1395 msgid "Please remove selections from the secret keys.\n" @@ -2191,14 +2189,12 @@ msgid "Please select at most one secondary key.\n" msgstr "Seleziona al massimo una chiave secondaria.\n" #: g10/keyedit.c:1405 -#, fuzzy msgid "Changing expiration time for a secondary key.\n" -msgstr "Modifico il tempo di scadenza per una chiave secondaria.\n" +msgstr "Cambio la data di scadenza per una chiave secondaria.\n" #: g10/keyedit.c:1407 -#, fuzzy msgid "Changing expiration time for the primary key.\n" -msgstr "Modifico il tempo di scadenza per la chiave primaria.\n" +msgstr "Cambio la data di scadenza per la chiave primaria.\n" #: g10/keyedit.c:1448 msgid "You can't change the expiration date of a v3 key\n" @@ -2285,17 +2281,16 @@ msgid "original file name='%.*s'\n" msgstr "nome del file originale='%.*s'\n" #: g10/mainproc.c:505 g10/mainproc.c:514 -#, fuzzy msgid "WARNING: invalid notation data found\n" -msgstr "Non sono stati trovati dati OpenPGP validi.\n" +msgstr "ATTENZIONE: trovati dati di una nota non validi\n" #: g10/mainproc.c:517 msgid "Notation: " -msgstr "" +msgstr "Nota: " #: g10/mainproc.c:524 msgid "Policy: " -msgstr "" +msgstr "Policy: " #: g10/mainproc.c:929 msgid "signature verification suppressed\n" @@ -2638,9 +2633,8 @@ msgid "%s: failed to append a record: %s\n" msgstr "%s: accodatura a un record fallita: %s\n" #: g10/tdbio.c:1630 -#, fuzzy msgid "the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n" -msgstr "Il trustdb è danneggiato; eseguire \"gpgm --fix-trust-db\".\n" +msgstr "Il trustdb è danneggiato; eseguire \"gpg --fix-trust-db\".\n" #: g10/trustdb.c:163 #, c-format @@ -3099,7 +3093,7 @@ msgstr "Sovrascrivo (s/N)? " #: g10/openfile.c:97 #, c-format msgid "%s: unknown suffix\n" -msgstr "" +msgstr "%s: suffisso sconosciuto\n" #: g10/openfile.c:122 msgid "writing to stdout\n" @@ -3241,23 +3235,20 @@ msgid "keyedit.remove.subkey.okay" msgstr "keyedit.remove.subkey.okay" #: g10/helptext.c:176 -#, fuzzy msgid "keyedit.delsig.valid" -msgstr "keyedit.sign_all.okay" +msgstr "keyedit.delsig.valid" #: g10/helptext.c:181 -#, fuzzy msgid "keyedit.delsig.unknown" -msgstr "keyedit.sign_all.okay" +msgstr "keyedit.delsig.unknown" #: g10/helptext.c:187 -#, fuzzy msgid "keyedit.delsig.invalid" -msgstr "keyedit.sign_all.okay" +msgstr "keyedit.delsig.invalid" #: g10/helptext.c:191 msgid "keyedit.delsig.selfsig" -msgstr "" +msgstr "keyedit.delsig.selfsig<" #: g10/helptext.c:200 msgid "passphrase.enter" @@ -3283,30 +3274,3 @@ msgstr "Non #, c-format msgid "No help available for `%s'" msgstr "Non è disponibile un aiuto per `%s'" - -#~ msgid "can't open file: %s\n" -#~ msgstr "impossibile aprire il file: %s\n" - -#~ msgid "read error: %s\n" -#~ msgstr "errore di lettura: %s\n" - -#~ msgid "can't write to keyring: %s\n" -#~ msgstr "impossibile scrivere sul portachiavi pubblico: %s\n" - -#~ msgid "writing keyblock\n" -#~ msgstr "scrittura del keyblock\n" - -#~ msgid "can't write keyblock: %s\n" -#~ msgstr "impossibile aprire il keyblock: %s\n" - -#~ msgid "can't lock secret keyring: %s\n" -#~ msgstr "impossibile bloccare il portachiavi segreto: %s\n" - -#~ msgid "can't write keyring: %s\n" -#~ msgstr "impossibile scrivere il portachiavi: %s\n" - -#~ msgid "encrypted message is valid\n" -#~ msgstr "il messaggio cifrato è valido\n" - -#~ msgid "Can't check MDC: %s\n" -#~ msgstr "Impossibile controllare il MDC: %s\n" diff --git a/util/ChangeLog b/util/ChangeLog index 3435472c5..35e69fb31 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,8 @@ +Tue Jun 29 21:44:25 CEST 1999 Werner Koch + + + * secmem.c (USE_CAPABILITIES): Capabilities support (Remi). + Sat Jun 26 12:15:59 CEST 1999 Werner Koch diff --git a/util/secmem.c b/util/secmem.c index 8f7c428e4..35a265408 100644 --- a/util/secmem.c +++ b/util/secmem.c @@ -29,6 +29,9 @@ #include #include #include + #ifdef USE_CAPABILITIES + #include + #endif #endif #include "types.h" @@ -80,7 +83,26 @@ print_warn(void) static void lock_pool( void *p, size_t n ) { - #ifdef HAVE_MLOCK + #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK) + int err; + + cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); + err = mlock( p, n ); + if( err && errno ) + err = errno; + cap_set_proc( cap_from_text("cap_ipc_lock+p") ); + + if( err ) { + if( errno != EPERM + #ifdef EAGAIN /* OpenBSD returns this */ + && errno != EAGAIN + #endif + ) + log_error("can´t lock memory: %s\n", strerror(err)); + show_warning = 1; + } + + #elif defined(HAVE_MLOCK) uid_t uid; int err; @@ -216,7 +238,11 @@ void secmem_init( size_t n ) { if( !n ) { - #ifndef HAVE_DOSISH_SYSTEM + #ifdef USE_CAPABILITIES + /* drop all capabilities */ + cap_set_proc( cap_from_text("all-eip") ); + + #elif !defined(HAVE_DOSISH_SYSTEM) uid_t uid; disable_secmem=1;