diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/ChangeLog | 22 | ||||
-rw-r--r-- | g10/armor.c | 29 | ||||
-rw-r--r-- | g10/g10.c | 12 | ||||
-rw-r--r-- | g10/getkey.c | 37 | ||||
-rw-r--r-- | g10/keygen.c | 6 | ||||
-rw-r--r-- | g10/keylist.c | 1 | ||||
-rw-r--r-- | g10/mainproc.c | 6 | ||||
-rw-r--r-- | g10/options.h | 1 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 13 | ||||
-rw-r--r-- | g10/ringedit.c | 91 | ||||
-rw-r--r-- | g10/signal.c | 12 | ||||
-rw-r--r-- | g10/tdbio.c | 78 | ||||
-rw-r--r-- | g10/tdbio.h | 10 | ||||
-rw-r--r-- | g10/trustdb.c | 253 |
14 files changed, 410 insertions, 161 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index 8a09ff324..61551dc5d 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,25 @@ +Wed Feb 10 17:15:39 CET 1999 Werner Koch <[email protected]> + + * g10.c (main): check for development version now in configure + + * tdbio.c (tdbio_write_record): Add uid.validity + (tdbio_read_record) : Ditto. + (tdbio_dump_record) : Ditto. + + * keygen.c (keygen_add_std_prefs): Replaced Blowfish by Twofish, + removed MD5 and Tiger. + * pubkey-enc.c (get_it): Suppress warning about missing Blowfish + in preferences in certain cases. + + * ringedit.c (lock_rentry,unlock_rentry): New. + + * getkey.c (key_byname): Pass ret_kb down to lookup_xx. + + * armor.c (armor_filter): No output of of empty comment lines. + Add option --no-version to suppress the output of the version string. + + * getkey.c: Release the getkey context for auto context variables. + Sun Jan 24 18:16:26 CET 1999 Werner Koch <[email protected]> * getkey.c: Changed the internal design to allow simultaneous diff --git a/g10/armor.c b/g10/armor.c index 663e824a6..5aba3322a 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -876,23 +876,26 @@ armor_filter( void *opaque, int control, iobuf_writestr(a, "-----"); iobuf_writestr(a, head_strings[afx->what] ); iobuf_writestr(a, "-----\n"); - iobuf_writestr(a, "Version: GnuPG v" VERSION " (" - PRINTABLE_OS_NAME ")\n"); + if( !opt.no_version ) + iobuf_writestr(a, "Version: GnuPG v" VERSION " (" + PRINTABLE_OS_NAME ")\n"); if( opt.comment_string ) { const char *s = opt.comment_string; - iobuf_writestr(a, "Comment: " ); - for( ; *s; s++ ) { - if( *s == '\n' ) - iobuf_writestr(a, "\\n" ); - else if( *s == '\r' ) - iobuf_writestr(a, "\\r" ); - else if( *s == '\v' ) - iobuf_writestr(a, "\\v" ); - else - iobuf_put(a, *s ); + if( *s ) { + iobuf_writestr(a, "Comment: " ); + for( ; *s; s++ ) { + if( *s == '\n' ) + iobuf_writestr(a, "\\n" ); + else if( *s == '\r' ) + iobuf_writestr(a, "\\r" ); + else if( *s == '\v' ) + iobuf_writestr(a, "\\v" ); + else + iobuf_put(a, *s ); + } + iobuf_put(a, '\n' ); } - iobuf_put(a, '\n' ); } else iobuf_writestr(a, @@ -117,6 +117,7 @@ enum cmd_and_opt_values { aNull = 0, oDebugAll, oStatusFD, oNoComment, + oNoVersion, oCompletesNeeded, oMarginalsNeeded, oMaxCertDepth, @@ -307,6 +308,7 @@ static ARGPARSE_OPTS opts[] = { { oRunAsShmCP, "run-as-shm-coprocess", 4, "@" }, { oSetFilename, "set-filename", 2, "@" }, { oComment, "comment", 2, "@" }, + { oNoVersion, "no-version", 0, "@"}, { oNotDashEscaped, "not-dash-escaped", 0, "@" }, { oEscapeFrom, "escape-from-lines", 0, "@" }, { oLockOnce, "lock-once", 0, "@" }, @@ -716,6 +718,7 @@ main( int argc, char **argv ) opt.verbose = 0; opt.list_sigs=0; break; case oQuickRandom: quick_random_gen(1); break; case oNoComment: opt.no_comment=1; break; + case oNoVersion: opt.no_version=1; break; case oCompletesNeeded: opt.completes_needed = pargs.r.ret_int; break; case oMarginalsNeeded: opt.marginals_needed = pargs.r.ret_int; break; case oMaxCertDepth: opt.max_cert_depth = pargs.r.ret_int; break; @@ -810,6 +813,9 @@ main( int argc, char **argv ) if( greeting ) { tty_printf("%s %s; %s\n", strusage(11), strusage(13), strusage(14) ); tty_printf("%s\n", strusage(15) ); + #ifdef IS_DEVELOPMENT_VERSION + log_info("NOTE: this is a development version!\n"); + #endif } secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */ @@ -859,12 +865,6 @@ main( int argc, char **argv ) log_error(_("invalid S2K mode; must be 0, 1 or 3\n")); } - { const char *p = strusage(13); - for( ; *p && (isdigit(*p) || *p=='.'); p++ ) - ; - if( *p ) - log_info("NOTE: this is a development version!\n"); - } if( log_get_errorcount(0) ) g10_exit(2); diff --git a/g10/getkey.c b/g10/getkey.c index 770aa5811..f7558703d 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -38,9 +38,9 @@ #define MAX_PK_CACHE_ENTRIES 50 #define MAX_UID_CACHE_ENTRIES 50 -/* Aa map of the all characters valid used for word_match() +/* A map of the all characters valid used for word_match() * Valid characters are in in this table converted to uppercase. - * becuase the upper 128 bytes have special meanin, we assume + * because the upper 128 bytes have special meaning, we assume * that they are all valid. * Note: We must use numerical values here in case that this program * will be converted to those little blue HAL9000s with their strange @@ -95,6 +95,7 @@ struct getkey_ctx_s { KBPOS kbpos; int last_rc; ulong count; + int not_allocated; int nitems; getkey_item_t items[1]; }; @@ -322,11 +323,13 @@ get_pubkey( PKT_public_key *pk, u32 *keyid ) /* do a lookup */ { struct getkey_ctx_s ctx; memset( &ctx, 0, sizeof ctx ); + ctx.not_allocated = 1; ctx.nitems = 1; ctx.items[0].mode = 11; ctx.items[0].keyid[0] = keyid[0]; ctx.items[0].keyid[1] = keyid[1]; rc = lookup_pk( &ctx, pk, NULL ); + get_pubkey_end( &ctx ); } if( !rc ) goto leave; @@ -371,11 +374,13 @@ get_seckey( PKT_secret_key *sk, u32 *keyid ) struct getkey_ctx_s ctx; memset( &ctx, 0, sizeof ctx ); + ctx.not_allocated = 1; ctx.nitems = 1; ctx.items[0].mode = 11; ctx.items[0].keyid[0] = keyid[0]; ctx.items[0].keyid[1] = keyid[1]; rc = lookup_sk( &ctx, sk, NULL ); + get_seckey_end( &ctx ); if( !rc ) { /* check the secret key (this may prompt for a passprase to * unlock the secret key @@ -395,14 +400,18 @@ int get_primary_seckey( PKT_secret_key *sk, u32 *keyid ) { struct getkey_ctx_s ctx; + int rc; memset( &ctx, 0, sizeof ctx ); + ctx.not_allocated = 1; ctx.primary = 1; ctx.nitems = 1; ctx.items[0].mode = 11; ctx.items[0].keyid[0] = keyid[0]; ctx.items[0].keyid[1] = keyid[1]; - return lookup_sk( &ctx, sk, NULL ); + rc = lookup_sk( &ctx, sk, NULL ); + get_seckey_end( &ctx ); + return rc; } @@ -421,11 +430,13 @@ seckey_available( u32 *keyid ) sk = m_alloc_clear( sizeof *sk ); memset( &ctx, 0, sizeof ctx ); + ctx.not_allocated = 1; ctx.nitems = 1; ctx.items[0].mode = 11; ctx.items[0].keyid[0] = keyid[0]; ctx.items[0].keyid[1] = keyid[1]; rc = lookup_sk( &ctx, sk, NULL ); + get_seckey_end( &ctx ); free_secret_key( sk ); return rc; } @@ -653,9 +664,9 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist, /* and call the lookup function */ ctx->primary = 1; /* we want to look for the primary key only */ if( sk ) - rc = lookup_sk( ctx, sk, NULL ); + rc = lookup_sk( ctx, sk, ret_kb ); else - rc = lookup_pk( ctx, pk, NULL ); + rc = lookup_pk( ctx, pk, ret_kb ); if( retctx ) /* caller wants the context */ *retctx = ctx; @@ -733,7 +744,8 @@ get_pubkey_end( GETKEY_CTX ctx ) enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */ for(n=0; n < ctx->nitems; n++ ) m_free( ctx->items[n].namebuf ); - m_free( ctx ); + if( !ctx->not_allocated ) + m_free( ctx ); } } @@ -748,10 +760,12 @@ get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint, size_t fprint_len) if( fprint_len == 20 || fprint_len == 16 ) { struct getkey_ctx_s ctx; memset( &ctx, 0, sizeof ctx ); + ctx.not_allocated = 1; ctx.nitems = 1; ctx.items[0].mode = fprint_len; memcpy( ctx.items[0].fprint, fprint, fprint_len ); rc = lookup_pk( &ctx, pk, NULL ); + get_pubkey_end( &ctx ); } else rc = G10ERR_GENERAL; /* Oops */ @@ -772,10 +786,12 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint, if( fprint_len == 20 || fprint_len == 16 ) { struct getkey_ctx_s ctx; memset( &ctx, 0, sizeof ctx ); + ctx.not_allocated = 1; ctx.nitems = 1; ctx.items[0].mode = fprint_len; memcpy( ctx.items[0].fprint, fprint, fprint_len ); rc = lookup_pk( &ctx, pk, ret_keyblock ); + get_pubkey_end( &ctx ); } else rc = G10ERR_GENERAL; /* Oops */ @@ -806,10 +822,12 @@ get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect ) struct getkey_ctx_s ctx; memset( &ctx, 0, sizeof ctx ); + ctx.not_allocated = 1; ctx.primary = 1; ctx.nitems = 1; ctx.items[0].mode = 15; rc = lookup_sk( &ctx, sk, NULL ); + get_seckey_end( &ctx ); } else { add_to_strlist( &namelist, name ); @@ -868,7 +886,8 @@ get_seckey_end( GETKEY_CTX ctx ) enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */ for(n=0; n < ctx->nitems; n++ ) m_free( ctx->items[n].namebuf ); - m_free( ctx ); + if( !ctx->not_allocated ) + m_free( ctx ); } } @@ -1600,7 +1619,7 @@ lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock ) k = find_first( ctx->keyblock, pk ); else if( item->mode == 16 || item->mode == 20 ) k = find_by_fpr( ctx->keyblock, pk, - item->name, item->mode ); + item->fprint, item->mode ); else BUG(); if( k ) { @@ -1687,7 +1706,7 @@ lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock ) k = find_first_sk( ctx->keyblock, sk ); else if( item->mode == 16 || item->mode == 20 ) k = find_by_fpr_sk( ctx->keyblock, sk, - item->name, item->mode ); + item->fprint, item->mode ); else BUG(); if( k ) { diff --git a/g10/keygen.c b/g10/keygen.c index 7431d8c61..12fa9422c 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -83,15 +83,13 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque ) keygen_add_key_expire( sig, opaque ); - buf[0] = CIPHER_ALGO_BLOWFISH; + buf[0] = CIPHER_ALGO_TWOFISH; buf[1] = CIPHER_ALGO_CAST5; build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 2 ); buf[0] = DIGEST_ALGO_RMD160; buf[1] = DIGEST_ALGO_SHA1; - buf[2] = DIGEST_ALGO_TIGER; - buf[3] = DIGEST_ALGO_MD5; - build_sig_subpkt( sig, SIGSUBPKT_PREF_HASH, buf, 4 ); + build_sig_subpkt( sig, SIGSUBPKT_PREF_HASH, buf, 2 ); buf[0] = 2; buf[1] = 1; diff --git a/g10/keylist.c b/g10/keylist.c index 2a471b86c..0bfdb7725 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -169,6 +169,7 @@ list_keyblock( KBNODE keyblock, int secret ) node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY ); if( !node ) { log_error("Oops; key lost!\n"); + dump_kbnode( keyblock ); return; } diff --git a/g10/mainproc.c b/g10/mainproc.c index 2e5575dd8..0b3582c50 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -252,7 +252,11 @@ proc_plaintext( CTX c, PACKET *pkt ) free_md_filter_context( &c->mfx ); c->mfx.md = md_open( 0, 0); /* fixme: we may need to push the textfilter if we have sigclass 1 - * and no armoring - Not yet tested */ + * and no armoring - Not yet tested + * Hmmm, why don't we need it at all if we have sigclass 1 + * Should we assume that plaintext in mode 't' has always sigclass 1?? + * See: Russ Allbery's mail 1999-02-09 + */ any = clearsig = 0; for(n=c->list; n; n = n->next ) { if( n->pkt->pkttype == PKT_ONEPASS_SIG ) { diff --git a/g10/options.h b/g10/options.h index d7450dba8..39564fb2e 100644 --- a/g10/options.h +++ b/g10/options.h @@ -47,6 +47,7 @@ struct { int def_compress_algo; const char *def_secret_key; int no_comment; + int no_version; int marginals_needed; int completes_needed; int max_cert_depth; diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index f662c6206..af77a1e52 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -31,6 +31,7 @@ #include "trustdb.h" #include "cipher.h" #include "status.h" +#include "options.h" #include "i18n.h" static int get_it( PKT_pubkey_enc *k, @@ -179,9 +180,17 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) else if( !pk->local_id && query_trust_record(pk) ) log_error("can't check algorithm against preferences\n"); else if( dek->algo != CIPHER_ALGO_3DES - && !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, dek->algo ) ) - log_info(_("NOTE: cipher algorithm %d not found in preferences\n"), + && !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, dek->algo ) ) { + /* Don't print a note while we are not on verbose mode, + * the cipher is blowfish and the preferences have twofish + * listed */ + if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH + || !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, + CIPHER_ALGO_TWOFISH ) ) + log_info(_( + "NOTE: cipher algorithm %d not found in preferences\n"), dek->algo ); + } free_public_key( pk ); rc = 0; } diff --git a/g10/ringedit.c b/g10/ringedit.c index 4a97f78f8..d5ac6ac77 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -72,12 +72,13 @@ struct resource_table_struct { GDBM_FILE dbf; #endif enum resource_type rt; + DOTLOCK lockhd; + int is_locked; }; typedef struct resource_table_struct RESTBL; #define MAX_RESOURCES 10 static RESTBL resource_table[MAX_RESOURCES]; -static const char *keyring_lock; static int search( PACKET *pkt, KBPOS *kbpos, int secret ); @@ -117,15 +118,40 @@ fatal_gdbm_error( const char *string ) #endif /* HAVE_LIBGDBM */ + +/**************** + * Hmmm, how to avoid deadlock? They should not happen if everyone + * locks the key resources in the same order; but who knows. + * A solution is to use only one lock file in the gnupg homedir but + * what will happen with key resources which normally don't belong + * to the gpg homedir? + */ static void -cleanup( void ) +lock_rentry( RESTBL *rentry ) { - if( keyring_lock ) { - release_dotlock( keyring_lock ); - keyring_lock = NULL; + if( !rentry->lockhd ) { + rentry->lockhd = create_dotlock( rentry->fname ); + if( !rentry->lockhd ) + log_fatal("can't allocate lock for `%s'\n", rentry->fname ); + rentry->is_locked = 0; + } + if( !rentry->is_locked ) { + if( make_dotlock( rentry->lockhd, -1 ) ) + log_fatal("can't lock `%s'\n", rentry->fname ); + rentry->is_locked = 1; } } +static void +unlock_rentry( RESTBL *rentry ) +{ + if( opt.lock_once ) + return; + if( !release_dotlock( rentry->lockhd ) ) + rentry->is_locked = 0; +} + + /**************************************************************** ****************** public functions **************************** ****************************************************************/ @@ -162,7 +188,6 @@ enum_keyblock_resources( int *sequence, int secret ) int add_keyblock_resource( const char *url, int force, int secret ) { - static int initialized = 0; static int any_secret, any_public; const char *resname = url; IOBUF iobuf = NULL; @@ -171,10 +196,6 @@ add_keyblock_resource( const char *url, int force, int secret ) int rc = 0; enum resource_type rt = rt_UNKNOWN; - if( !initialized ) { - initialized = 1; - atexit( cleanup ); - } /* Do we have an URL? * gnupg-gdbm:filename := this is a GDBM resource @@ -190,7 +211,7 @@ add_keyblock_resource( const char *url, int force, int secret ) rt = rt_GDBM; resname += 11; } - #ifndef __MINGW32__ + #ifndef HAVE_DRIVE_LETTERS else if( strchr( resname, ':' ) ) { log_error("%s: invalid URL\n", url ); rc = G10ERR_GENERAL; @@ -264,7 +285,7 @@ add_keyblock_resource( const char *url, int force, int secret ) if( access(filename, F_OK) ) { if( strlen(filename) >= 7 && !strcmp(filename+strlen(filename)-7, "/.gnupg") ) { - #if __MINGW32__ + #ifdef HAVE_DOSISH_SYSTEM if( mkdir(filename) ) #else if( mkdir(filename, S_IRUSR|S_IWUSR|S_IXUSR) ) @@ -298,10 +319,10 @@ add_keyblock_resource( const char *url, int force, int secret ) else log_info(_("%s: keyring created\n"), filename ); } - #if __MINGW32__ || 1 - /* must close it again */ + #if HAVE_DOSISH_SYSTEM || 1 iobuf_close( iobuf ); iobuf = NULL; + /* must close it again */ #endif break; @@ -1039,7 +1060,7 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname ) kbpos->rt = rt_RING; kbpos->valid = 0; - #if __MINGW32__ || 1 + #if HAVE_DOSISH_SYSTEM || 1 assert(!iobuf); iobuf = iobuf_open( fname ); if( !iobuf ) { @@ -1084,7 +1105,7 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname ) leave: free_packet(&pkt); set_packet_list_mode(save_mode); - #if __MINGW32__ || 1 + #if HAVE_DOSISH_SYSTEM || 1 iobuf_close(iobuf); #endif return rc; @@ -1276,10 +1297,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) if( kbpos->fp ) BUG(); /* not allowed with such a handle */ - if( !keyring_lock ); - keyring_lock = make_dotlock( rentry->fname, -1 ); - if( !keyring_lock ) - log_fatal("can't lock `%s'\n", rentry->fname ); + lock_rentry( rentry ); /* open the source file */ fp = iobuf_open( rentry->fname ); @@ -1290,10 +1308,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) newfp = iobuf_create( rentry->fname ); if( !newfp ) { log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno)); - if( !opt.lock_once ) { - release_dotlock( keyring_lock ); - keyring_lock = NULL; - } + unlock_rentry( rentry ); return G10ERR_OPEN_FILE; } else @@ -1305,28 +1320,19 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) log_error("build_packet(%d) failed: %s\n", node->pkt->pkttype, g10_errstr(rc) ); iobuf_cancel(newfp); - if( !opt.lock_once ) { - release_dotlock( keyring_lock ); - keyring_lock = NULL; - } + unlock_rentry( rentry ); return G10ERR_WRITE_FILE; } } if( iobuf_close(newfp) ) { log_error("%s: close failed: %s\n", rentry->fname, strerror(errno)); - if( !opt.lock_once ) { - release_dotlock( keyring_lock ); - keyring_lock = NULL; - } + unlock_rentry( rentry ); return G10ERR_CLOSE_FILE; } if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) { log_error("%s: chmod failed: %s\n", rentry->fname, strerror(errno) ); - if( !opt.lock_once ) { - release_dotlock( keyring_lock ); - keyring_lock = NULL; - } + unlock_rentry( rentry ); return G10ERR_WRITE_FILE; } return 0; @@ -1338,7 +1344,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) } /* create the new file */ - #ifdef __MINGW32__ + #ifdef USE_ONLY_8DOT3 /* Here is another Windoze bug?: * you cant rename("pubring.gpg.tmp", "pubring.gpg"); * but rename("pubring.gpg.tmp", "pubring.aaa"); @@ -1451,7 +1457,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) goto leave; } /* if the new file is a secring, restrict the permissions */ - #ifndef __MINGW32__ + #ifndef HAVE_DOSISH_SYSTEM if( rentry->secret ) { if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) { log_error("%s: chmod failed: %s\n", @@ -1464,7 +1470,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) /* rename and make backup file */ if( !rentry->secret ) { /* but not for secret keyrings */ - #ifdef __MINGW32__ + #ifdef HAVE_DOSISH_SYSTEM remove( bakfname ); #endif if( rename( rentry->fname, bakfname ) ) { @@ -1474,7 +1480,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) goto leave; } } - #ifdef __MINGW32__ + #ifdef HAVE_DOSISH_SYSTEM remove( rentry->fname ); #endif if( rename( tmpfname, rentry->fname ) ) { @@ -1492,10 +1498,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) } leave: - if( !opt.lock_once ) { - release_dotlock( keyring_lock ); - keyring_lock = NULL; - } + unlock_rentry( rentry ); m_free(bakfname); m_free(tmpfname); return rc; diff --git a/g10/signal.c b/g10/signal.c index 364fb47a4..29f99c64b 100644 --- a/g10/signal.c +++ b/g10/signal.c @@ -70,7 +70,7 @@ got_usr_signal( int sig ) caught_sigusr1 = 1; } -#ifndef __MINGW32__ +#ifndef HAVE_DOSISH_SYSTEM static void do_sigaction( int sig, struct sigaction *nact ) { @@ -85,7 +85,7 @@ do_sigaction( int sig, struct sigaction *nact ) void init_signals() { - #ifndef __MINGW32__ + #ifndef HAVE_DOSISH_SYSTEM struct sigaction nact; nact.sa_handler = got_fatal_signal; @@ -100,7 +100,7 @@ init_signals() nact.sa_handler = got_usr_signal; sigaction( SIGUSR1, &nact, NULL ); nact.sa_handler = SIG_IGN; - sigaction( SIGPIPE, &nact, NULL ); + sigaction( SIGPIPE, &nact, NULL ); #endif } @@ -108,7 +108,7 @@ init_signals() void pause_on_sigusr( int which ) { - #ifndef __MINGW32__ + #ifndef HAVE_DOSISH_SYSTEM sigset_t mask, oldmask; assert( which == 1 ); @@ -127,7 +127,7 @@ pause_on_sigusr( int which ) static void do_block( int block ) { - #ifndef __MINGW32__ + #ifndef HAVE_DOSISH_SYSTEM static int is_blocked; static sigset_t oldmask; @@ -146,7 +146,7 @@ do_block( int block ) sigprocmask( SIG_SETMASK, &oldmask, NULL ); is_blocked = 0; } - #endif /*__MINGW32__*/ + #endif /*HAVE_DOSISH_SYSTEM*/ } diff --git a/g10/tdbio.c b/g10/tdbio.c index b69d6c3f0..2eddb4b2d 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -77,7 +77,8 @@ struct cmp_sdir_struct { static char *db_name; -static const char *lockname; +static DOTLOCK lockhandle; +static int is_locked; static int db_fd = -1; static int in_transaction; @@ -236,10 +237,12 @@ put_record_into_cache( ulong recno, const char *data ) int n = dirty_count / 5; /* discard some dirty entries */ if( !n ) n = 1; - if( !lockname ) - lockname = make_dotlock( db_name, -1 ); - if( !lockname ) - log_fatal("can't get a lock - giving up\n"); + if( !is_locked ) { + if( make_dotlock( lockhandle, -1 ) ) + log_fatal("can't acquire lock - giving up\n"); + else + is_locked = 1; + } for( unused = NULL, r = cache_list; r; r = r->next ) { if( r->flags.used && r->flags.dirty ) { int rc = write_cache_item( r ); @@ -254,8 +257,8 @@ put_record_into_cache( ulong recno, const char *data ) } } if( !opt.lock_once ) { - release_dotlock( lockname ); - lockname=NULL; + if( !release_dotlock( lockhandle ) ) + is_locked = 0; } assert( unused ); r = unused; @@ -287,17 +290,20 @@ tdbio_sync() CACHE_CTRL r; int did_lock = 0; + if( db_fd == -1 ) + open_db(); if( in_transaction ) log_bug("tdbio: syncing while in transaction\n"); if( !cache_is_dirty ) return 0; - if( !lockname ) { - lockname = make_dotlock( db_name, -1 ); + if( !is_locked ) { + if( make_dotlock( lockhandle, -1 ) ) + log_fatal("can't acquire lock - giving up\n"); + else + is_locked = 1; did_lock = 1; - if( !lockname ) - log_fatal("can't get a lock - giving up\n"); } for( r = cache_list; r; r = r->next ) { if( r->flags.used && r->flags.dirty ) { @@ -308,8 +314,8 @@ tdbio_sync() } cache_is_dirty = 0; if( did_lock && !opt.lock_once ) { - release_dotlock( lockname ); - lockname=NULL; + if( !release_dotlock( lockhandle ) ) + is_locked = 0; } return 0; } @@ -344,17 +350,19 @@ tdbio_end_transaction() if( !in_transaction ) log_bug("tdbio: no active transaction\n"); - if( !lockname ) - lockname = make_dotlock( db_name, -1 ); - if( !lockname ) - log_fatal("can't get a lock - giving up\n"); + if( !is_locked ) { + if( make_dotlock( lockhandle, -1 ) ) + log_fatal("can't acquire lock - giving up\n"); + else + is_locked = 1; + } block_all_signals(); in_transaction = 0; rc = tdbio_sync(); unblock_all_signals(); if( !opt.lock_once ) { - release_dotlock( lockname ); - lockname=NULL; + if( !release_dotlock( lockhandle ) ) + is_locked = 0; } return rc; } @@ -392,9 +400,9 @@ tdbio_cancel_transaction() static void cleanup(void) { - if( lockname ) { - release_dotlock(lockname); - lockname = NULL; + if( is_locked ) { + if( !release_dotlock(lockhandle) ) + is_locked = 0; } } @@ -428,7 +436,7 @@ tdbio_set_dbname( const char *new_dbname, int create ) if( access( fname, F_OK ) ) { if( strlen(fname) >= 7 && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) { - #if __MINGW32__ + #if HAVE_DOSISH_SYSTEM if( mkdir( fname ) ) #else if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) ) @@ -450,7 +458,7 @@ tdbio_set_dbname( const char *new_dbname, int create ) fclose(fp); m_free(db_name); db_name = fname; - #ifdef __MINGW32__ + #ifdef HAVE_DOSISH_SYSTEM db_fd = open( db_name, O_RDWR | O_BINARY ); #else db_fd = open( db_name, O_RDWR ); @@ -501,7 +509,10 @@ open_db() TRUSTREC rec; assert( db_fd == -1 ); - #ifdef __MINGW32__ + lockhandle = create_dotlock( db_name ); + if( !lockhandle ) + log_fatal( _("%s: can't create lock\n"), db_name ); + #ifdef HAVE_DOSISH_SYSTEM db_fd = open( db_name, O_RDWR | O_BINARY ); #else db_fd = open( db_name, O_RDWR ); @@ -970,6 +981,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp ) rec->r.uid.prefrec, rec->r.uid.siglist, rec->r.uid.namehash[18], rec->r.uid.namehash[19]); + if( rec->r.uid.uidflags & UIDF_VALVALID ) + fprintf( fp, ", v=%02x", rec->r.uid.validity ); if( rec->r.uid.uidflags & UIDF_CHECKED ) { if( rec->r.uid.uidflags & UIDF_VALID ) fputs(", valid", fp ); @@ -1155,7 +1168,18 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) rec->r.uid.prefrec = buftoulong(p); p += 4; rec->r.uid.siglist = buftoulong(p); p += 4; rec->r.uid.uidflags = *p++; - p ++; + rec->r.uid.validity = *p++; + switch( rec->r.uid.validity ) { + case 0: + case TRUST_UNDEFINED: + case TRUST_NEVER: + case TRUST_MARGINAL: + case TRUST_FULLY: + case TRUST_ULTIMATE: + break; + default: + log_info("lid %lu: invalid validity value - cleared\n", recnum); + } memcpy( rec->r.uid.namehash, p, 20); break; case RECTYPE_PREF: /* preference record */ @@ -1278,7 +1302,7 @@ tdbio_write_record( TRUSTREC *rec ) ulongtobuf(p, rec->r.uid.prefrec); p += 4; ulongtobuf(p, rec->r.uid.siglist); p += 4; *p++ = rec->r.uid.uidflags; - p++; + *p++ = rec->r.uid.validity; memcpy( p, rec->r.uid.namehash, 20 ); p += 20; break; diff --git a/g10/tdbio.h b/g10/tdbio.h index 925c7f93c..62148d361 100644 --- a/g10/tdbio.h +++ b/g10/tdbio.h @@ -59,9 +59,10 @@ #define KEYF_EXPIRED 4 /* this key is expired */ #define KEYF_REVOKED 8 /* this key has been revoked */ -#define UIDF_CHECKED 1 /* user id has been checked - other bits are valid */ -#define UIDF_VALID 2 /* this is a valid user id */ -#define UIDF_REVOKED 8 /* this user id has been revoked */ +#define UIDF_CHECKED 1 /* user id has been checked - other bits are valid */ +#define UIDF_VALID 2 /* this is a valid user id */ +#define UIDF_REVOKED 8 /* this user id has been revoked */ +#define UIDF_VALVALID 16 /* the validity field is valid */ #define SIGF_CHECKED 1 /* signature has been checked - bits 0..6 are valid */ #define SIGF_VALID 2 /* the signature is valid */ @@ -98,7 +99,7 @@ struct trust_record { ulong cacherec; /* the cache record */ byte ownertrust; byte dirflags; - byte validity; /* calculated trustlevel */ + byte validity; /* calculated trustlevel over all uids */ } dir; struct { /* primary public key record */ ulong lid; @@ -114,6 +115,7 @@ struct trust_record { ulong prefrec; /* recno of preference record */ ulong siglist; /* list of valid signatures (w/o self-sig)*/ byte uidflags; + byte validity; /* calculated trustlevel of this uid */ byte namehash[20]; /* ripemd hash of the username */ } uid; struct { /* preference record */ diff --git a/g10/trustdb.c b/g10/trustdb.c index 674240a7b..34890c2da 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -104,6 +104,8 @@ static void release_lid_table( LOCAL_ID_TABLE tbl ); static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag ); static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag ); + + static void print_user_id( const char *text, u32 *keyid ); static void sort_tsl_list( TRUST_SEG_LIST *trust_seg_list ); static int list_sigs( ulong pubkey_id ); @@ -839,42 +841,13 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec, ulong rn, uidrn; int marginal=0; int fully=0; - LOCAL_ID_TABLE sigs_seen = NULL; + /*LOCAL_ID_TABLE sigs_seen = NULL;*/ if( depth >= max_depth ) /* max cert_depth reached */ return TRUST_UNDEFINED; - stack[depth].lid = drec->r.dir.lid; - stack[depth].otrust = drec->r.dir.ownertrust; - stack[depth].trust = 0; - { int i; - - for(i=0; i < depth; i++ ) - if( stack[i].lid == drec->r.dir.lid ) - return TRUST_UNDEFINED; /* closed (we already visited this lid) */ - } - if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) { - /* we are at the end of a path */ - TRUST_SEG_LIST tsl; - int i; - - stack[depth].trust = TRUST_ULTIMATE; - stack[depth].otrust = TRUST_ULTIMATE; - if( trust_seg_head ) { - /* we can now put copy our current stack to the trust_seg_list */ - tsl = m_alloc( sizeof *tsl + (depth+1)*sizeof( TRUST_INFO ) ); - for(i=0; i <= depth; i++ ) - tsl->path[i] = stack[i]; - tsl->pathlen = i; - tsl->next = *trust_seg_head; - *trust_seg_head = tsl; - } - return TRUST_ULTIMATE; - } - /* loop over all user-ids */ - if( !all ) - sigs_seen = new_lid_table(); + /*if( !all ) sigs_seen = new_lid_table();*/ for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) { TRUSTREC rec; /* used for uids and sigs */ ulong sigrn; @@ -888,7 +861,36 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec, if( (rec.r.uid.uidflags & UIDF_REVOKED) ) continue; /* user id has been revoked */ - /* loop over all signature records */ + stack[depth].lid = drec->r.dir.lid; + stack[depth].otrust = drec->r.dir.ownertrust; + stack[depth].trust = 0; + { int i; + + for(i=0; i < depth; i++ ) + if( stack[i].lid == drec->r.dir.lid ) + return TRUST_UNDEFINED; /* closed (we already visited this lid) */ + } + if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) { + /* we are at the end of a path */ + TRUST_SEG_LIST tsl; + int i; + + stack[depth].trust = TRUST_ULTIMATE; + stack[depth].otrust = TRUST_ULTIMATE; + if( trust_seg_head ) { + /* we can now put copy our current stack to the trust_seg_list */ + tsl = m_alloc( sizeof *tsl + (depth+1)*sizeof( TRUST_INFO ) ); + for(i=0; i <= depth; i++ ) + tsl->path[i] = stack[i]; + tsl->pathlen = i; + tsl->next = *trust_seg_head; + *trust_seg_head = tsl; + } + return TRUST_ULTIMATE; + } + + + /* loop over all signature records of this user id */ for( rn = rec.r.uid.siglist; rn; rn = sigrn ) { int i; @@ -917,11 +919,11 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec, } /* visit every signer only once (a signer may have - * signed more than one user ID) */ - if( sigs_seen && ins_lid_table_item( sigs_seen, - rec.r.sig.sig[i].lid, 0) ) - continue; /* we already have this one */ - + * signed more than one user ID) + * if( sigs_seen && ins_lid_table_item( sigs_seen, + * rec.r.sig.sig[i].lid, 0) ) + * continue; we already have this one + */ read_record( rec.r.sig.sig[i].lid, &tmp, 0 ); if( tmp.rectype != RECTYPE_DIR ) { if( tmp.rectype != RECTYPE_SDIR ) @@ -945,8 +947,7 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec, /* we have signed this key and only in this special case * we assume that this one is fully trusted */ if( !all ) { - if( sigs_seen ) - release_lid_table( sigs_seen ); + /*if( sigs_seen ) release_lid_table( sigs_seen );*/ return (stack[depth].trust = TRUST_FULLY); } } @@ -962,16 +963,14 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec, if( fully >= opt.completes_needed || marginal >= opt.marginals_needed ) { if( !all ) { - if( sigs_seen ) - release_lid_table( sigs_seen ); + /*if( sigs_seen ) release_lid_table( sigs_seen );*/ return (stack[depth].trust = TRUST_FULLY); } } } } } - if( sigs_seen ) - release_lid_table( sigs_seen ); + /*if( sigs_seen ) release_lid_table( sigs_seen ); */ if( all && ( fully >= opt.completes_needed || marginal >= opt.marginals_needed ) ) { return (stack[depth].trust = TRUST_FULLY ); @@ -983,6 +982,145 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec, } +typedef struct { + ulong lid; + ulong uid; +} CERT_ITEM; + +/* structure to hold certification chains. Item[nitems-1] is the + * ultimateley trusted key, item[0] is the key which + * is introduced, indices [1,(nitems-2)] are all introducers. + */ +typedef struct cert_chain *CERT_CHAIN; +struct cert_chain { + CERT_CHAIN next; + int dups; + int nitems; + CERT_ITEM items[1]; +}; + + + +/**************** + * Copy all items to the set SET_HEAD in a way that the requirements + * of a CERT_CHAIN are met. + */ +static void +add_cert_items_to_set( CERT_CHAIN *set_head, CERT_ITEM *items, int nitems ) +{ + CERT_CHAIN ac; + int i; + + ac = m_alloc_clear( sizeof *ac + (nitems-1)*sizeof(CERT_ITEM) ); + ac->nitems = nitems; + for(i=0; i < nitems; i++ ) + ac->items[i] = items[i]; + ac->next = *set_head; + *set_head = ac; +} + + +/**************** + * Find all certification paths of a given LID. + * Limit the search to MAX_DEPTH. stack is a helper variable which + * should have been allocated with size max_depth, stack[0] should + * be setup to the key we are investigating, so the minimal depth + * we should ever see in this function is 1. + * Returns: -1 max_depth reached + * 0 no paths found + * 1 ultimately trusted key found + * certchain_set must be a valid set or point to NULL; this function + * may modifiy it. + */ +static int +find_cert_chain( ulong lid, int depth, int max_depth, + CERT_ITEM *stack, CERT_CHAIN *cert_chain_set ) +{ + TRUSTREC dirrec; + TRUSTREC uidrec; + ulong uidrno; + + if( depth >= max_depth ) + return -1; + + stack[depth].lid = lid; + stack[depth].uid = 0; + + if( !qry_lid_table_flag( ultikey_table, lid, NULL ) ) { + /* this is an ultimately trusted key; + * which means that we have found the end of the chain: + * copy the chain to the set */ + add_cert_items_to_set( cert_chain_set, stack, depth+1 ); + return 1; + } + + + read_record( lid, &dirrec, 0 ); + if( dirrec.rectype != RECTYPE_DIR ) { + if( dirrec.rectype != RECTYPE_SDIR ) + log_debug("lid %lu, has rectype %d" + " - skipped\n", lid, dirrec.rectype ); + return 0; + } + /* Performance hint: add stuff to ignore this one when the + * assigned validity of the key is bad */ + + /* loop over all user ids */ + for( uidrno = dirrec.r.dir.uidlist; uidrno; uidrno = uidrec.r.uid.next ) { + TRUSTREC sigrec; + ulong sigrno; + + stack[depth].uid = uidrno; + read_record( uidrno, &uidrec, RECTYPE_UID ); + + if( !(uidrec.r.uid.uidflags & UIDF_CHECKED) ) + continue; /* user id has not been checked */ + if( !(uidrec.r.uid.uidflags & UIDF_VALID) ) + continue; /* user id is not valid */ + if( (uidrec.r.uid.uidflags & UIDF_REVOKED) ) + continue; /* user id has been revoked */ + + /* loop over all signature records */ + for(sigrno=uidrec.r.uid.siglist; sigrno; sigrno = sigrec.r.sig.next ) { + int i, j; + + read_record( sigrno, &sigrec, RECTYPE_SIG ); + + for(i=0; i < SIGS_PER_RECORD; i++ ) { + if( !sigrec.r.sig.sig[i].lid ) + continue; /* skip deleted sigs */ + if( !(sigrec.r.sig.sig[i].flag & SIGF_CHECKED) ) + continue; /* skip unchecked signatures */ + if( !(sigrec.r.sig.sig[i].flag & SIGF_VALID) ) + continue; /* skip invalid signatures */ + if( (sigrec.r.sig.sig[i].flag & SIGF_EXPIRED) ) + continue; /* skip expired signatures */ + if( (sigrec.r.sig.sig[i].flag & SIGF_REVOKED) ) + continue; /* skip revoked signatures */ + for(j=0; j < depth; j++ ) { + if( stack[j].lid == sigrec.r.sig.sig[i].lid ) + break; + } + if( j < depth ) + continue; /* avoid cycles as soon as possible */ + + if( find_cert_chain( sigrec.r.sig.sig[i].lid, + depth+1, max_depth, + stack, cert_chain_set ) > 0 ) { + /* ultimately trusted key found: + * no need to check more signatures of this uid */ + sigrec.r.sig.next = 0; + break; + } + } + } /* end loop over sig recs */ + } /* end loop over user ids */ + return 0; +} + + + + /**************** * Given the directory record of a key, check whether we can * find a path to an ultimately trusted key. We do this by @@ -1337,6 +1475,7 @@ void list_trust_path( const char *username ) { int rc; + ulong lid; TRUSTREC rec; TRUST_INFO *tmppath; TRUST_SEG_LIST trust_seg_list, tsl, tsl2; @@ -1357,8 +1496,10 @@ list_trust_path( const char *username ) assert( pk->local_id ); } } + lid = pk->local_id; free_public_key( pk ); + #if 0 /* collect the paths */ tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath ); trust_seg_list = NULL; @@ -1378,6 +1519,26 @@ list_trust_path( const char *username ) m_free( tsl ); } trust_seg_list = NULL; + #else /* test code */ + { + CERT_ITEM *stack; + CERT_CHAIN chains, r; + int i; + + chains = NULL; + stack = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *stack ); + find_cert_chain( lid, 0, opt.max_cert_depth, stack, &chains); + m_free( stack ); + /* dump chains */ + for(r=chains; r ; r = r->next ) { + printf("chain:" ); + for(i=0; i < r->nitems; i++ ) + printf(" %4lu/%-4lu", r->items[i].lid, r->items[i].uid ); + putchar('\n'); + } + + } + #endif } @@ -2719,15 +2880,17 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid, continue; /* skip deleted sigs */ } if( rec.r.sig.sig[i].lid == pk_lid ) { + #if 0 /* must take uid into account */ if( found_sig ) { log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s\n", (ulong)keyid[1], lid, uidhash[18], uidhash[19], (ulong)sig->keyid[1], - _("Duplicated certificate - deleted") ); + _("duplicated certificate - deleted") ); rec.r.sig.sig[i].lid = 0; rec.dirty = 1; continue; } + #endif found_sig = 1; } if( !recheck && !revoke && (rec.r.sig.sig[i].flag & SIGF_CHECKED) ) @@ -2811,7 +2974,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid, } } - if( found_sig ) + if( found_sig ) /* fixme: uid stuff */ return; /* at this point, we have verified, that the signature is not in |