diff --git a/NEWS b/NEWS index 66d650a2a..3354d3905 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ Noteworthy changes in the current CVS HEAD * Add Rijndael (AES) support. + * Removed gdbm support. + * Fixed problems with piping to/from other MS-Windows software * Expiration time of the primary key can be changed again. @@ -28,8 +30,6 @@ Noteworthy changes in the current CVS HEAD * Twofish and MDC enhanced encryption is now used. PGP 7 supports this. Older versions of GnuPG don't support it, so they should be upgraded to at least 1.0.2 - - Noteworthy changes in version 1.1.1 diff --git a/configure.in b/configure.in index 38d2c94db..133e65b13 100644 --- a/configure.in +++ b/configure.in @@ -184,7 +184,6 @@ MPI_OPT_FLAGS="" try_gettext=yes -try_gdbm=yes case "${target}" in *-*-mingw32*) # special stuff for Windoze NT @@ -194,7 +193,6 @@ case "${target}" in AC_DEFINE(HAVE_DOSISH_SYSTEM) AC_DEFINE(USE_SIMPLE_GETTEXT) try_gettext="no" - try_gdbm="no" ;; i?86-emx-os2 | i?86-*-os2*emx ) # OS/2 with the EMX environment @@ -202,7 +200,6 @@ case "${target}" in AC_DEFINE(HAVE_DRIVE_LETTERS) AC_DEFINE(HAVE_DOSISH_SYSTEM) try_gettext="no" - try_gdbm="no" ;; i?86-*-msdosdjgpp*) @@ -211,7 +208,6 @@ case "${target}" in AC_DEFINE(HAVE_DRIVE_LETTERS) AC_DEFINE(HAVE_DOSISH_SYSTEM) try_gettext="no" - try_gdbm="no" ;; *-*-freebsd*) @@ -331,19 +327,6 @@ fi AM_CONDITIONAL(COMPILE_AGENT, test x$compile_agent = xyes) - -dnl -dnl There are lot of misconfigured systems. We include -dnl gdbm support only if the lib and the header is installed. -dnl -if test "$try_gdbm" = yes; then -AC_CHECK_HEADERS(gdbm.h) -if test "$ac_cv_header_gdbm_h" = yes ; then - AC_CHECK_LIB(gdbm,gdbm_firstkey) -fi -fi - - dnl Solaris needs -lsocket and -lnsl. Unisys system includes dnl gethostbyname in libsocket but needs libnsl for socket. AC_CHECK_LIB(nsl, gethostbyname) diff --git a/g10/ChangeLog b/g10/ChangeLog index fb25e7fdc..127e54fa9 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,37 @@ +Fri Oct 6 14:29:16 CEST 2000 Werner Koch + + Started to rework the whole getkey/ringedit stuff to make + it simpler, correcter and faster. + + * parse-packet.c (parse_packet): Add a 3rd arg to return the filepos. + Changed all callers. + * getkey.c (classify_user_id): Add new mode 21. + (find_by_fpr): Find using this new mode. + (get_seckey_byname): New arg to return the context. Changed all + callers. + * keyid.c (unified_fingerprint_from_pk): New. + (unified_fingerprint_from_sk): New. + * ringedit.c (find_keyblock_bypk): Changed to use the unified + fingerprint for lookup. I can't see a reason why we did compare + the entire public key. + (find_keyblock_bysk): Ditto. + (search,cmp_pubkey,cmp_seckey): Removed. + (keyring_search, do_kbxf_search): Removed. + (locate_keyblock_by_fpr,locate_keyblock_by_keyid): Removed. + (find_keyblock_byname): Removed use o search function. + (find_secret_keyblock_byname): Ditto. + (merge_public_with_secret): Fixed removing subkeys. + (premerge_public_with_secret): New. + + * ringedit.c: Removed all GDBM support + + * ringedit.c (read_keyblock): Removed. + * ringedit.c (find_keyblock_byname,find_secret_keyblock_byname, + find_keyblock_bypk,find_keyblock_bysk): Moved from here to .... + * getkey.c: ... here. Changed first arg to return a keyblock and + changed all callers to merge the old read_keyblock() with these + functions. + Wed Oct 4 13:16:18 CEST 2000 Werner Koch * getkey.c (merge_selfsigs_main): Fixed for v3 keys. diff --git a/g10/delkey.c b/g10/delkey.c index 0c64d41a3..91413edd8 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -58,21 +58,14 @@ delete_key( const char *username, int secret ) int yes; /* search the userid */ - rc = secret? find_secret_keyblock_byname( &kbpos, username ) - : find_keyblock_byname( &kbpos, username ); + rc = secret? find_secret_keyblock_byname( &keyblock, username ) + : find_keyblock_byname( &keyblock, username ); if( rc ) { - log_error(_("%s: user not found\n"), username ); + log_error(_("%s: user not found: %s\n"), username, gpg_errstr(rc) ); write_status_text( STATUS_DELETE_PROBLEM, "1" ); goto leave; } - /* read the keyblock */ - rc = read_keyblock( &kbpos, &keyblock ); - if( rc ) { - log_error("%s: read problem: %s\n", username, gpg_errstr(rc) ); - goto leave; - } - /* get the keyid from the keyblock */ node = find_kbnode( keyblock, secret? PKT_SECRET_KEY:PKT_PUBLIC_KEY ); if( !node ) { diff --git a/g10/export.c b/g10/export.c index ddcc971d9..8b8ba489a 100644 --- a/g10/export.c +++ b/g10/export.c @@ -147,22 +147,15 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any ) } else { /* search the userid */ - rc = secret? find_secret_keyblock_byname( &kbpos, sl->d ) - : find_keyblock_byname( &kbpos, sl->d ); + rc = secret? find_secret_keyblock_byname( &keyblock, sl->d ) + : find_keyblock_byname( &keyblock, sl->d ); if( rc ) { log_error(_("%s: user not found: %s\n"), sl->d, gpg_errstr(rc)); rc = 0; continue; } - /* read the keyblock */ - rc = read_keyblock( &kbpos, &keyblock ); } - if( rc ) { - log_error(_("certificate read problem: %s\n"), gpg_errstr(rc)); - goto leave; - } - /* do not export keys which are incompatible with rfc2440 */ if( onlyrfc && (node = find_kbnode( keyblock, PKT_PUBLIC_KEY )) ) { diff --git a/g10/getkey.c b/g10/getkey.c index aa32dff74..a0fa44580 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -112,10 +112,6 @@ struct getkey_ctx_s { getkey_item_t items[1]; }; - - - - #if 0 static struct { int any; @@ -595,6 +591,8 @@ hextobyte( const byte *s ) * 12 = it is a trustdb index (keyid is looked up) * 16 = it is a 16 byte fingerprint * 20 = it is a 20 byte fingerprint + * 21 = Unified fingerprint :fpr:pk_algo: + * (We don't use pk_algo yet) * * if fprint is not NULL, it should be an array of at least 20 bytes. * @@ -606,6 +604,8 @@ hextobyte( const byte *s ) * must be in the range 0..9), this is considered a fingerprint. * - If the username starts with a left angle, we assume it is a complete * email address and look only at this part. + * - If the username starts with a colon we assume it is a unified + * key specfification. * - If the username starts with a '.', we assume it is the ending * part of an email address * - If the username starts with an '@', we assume it is a part of an @@ -674,7 +674,32 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint, keyid[0] = keyid[1] = 0; } break; - + + case ':': /*Unified fingerprint */ + { + const char *se, *si; + int i; + + se = strchr( ++s,':'); + if ( !se ) + return 0; + for (i=0,si=s; si < se; si++, i++ ) { + if ( !strchr("01234567890abcdefABCDEF", *si ) ) + return 0; /* invalid digit */ + } + if (i != 32 && i != 40) + return 0; /* invalid length of fpr*/ + if (fprint) { + for (i=0,si=s; si < se; i++, si +=2) + fprint[i] = hextobyte(si); + for ( ; i < 20; i++) + fprint[i]= 0; + } + s = se + 1; + mode = 21; + } + break; + default: if (s[0] == '0' && s[1] == 'x') { hexprefix = 1; @@ -803,7 +828,8 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist, /* if we don't use one of the exact key specifications, we assume that * the primary key is requested */ - if ( mode != 10 && mode != 11 && mode != 16 && mode == 20 ) + if ( mode != 10 && mode != 11 + && mode != 16 && mode == 20 && mode != 21 ) ctx->primary = 1; ctx->items[n].mode = mode; @@ -836,6 +862,10 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist, } } + if (!rc ) + log_debug ( "pk_byname: kbpos %s %lu %p\n", + ctx->kbpos.valid? "valid":"", + ctx->kbpos.offset, ctx->kbpos.fp ); release_kbnode ( help_kb ); if( retctx ) /* caller wants the context */ @@ -883,6 +913,7 @@ get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock ) return rc; } + void get_pubkey_end( GETKEY_CTX ctx ) { @@ -897,8 +928,66 @@ get_pubkey_end( GETKEY_CTX ctx ) } } + + +/**************** + * Combined function to search for a username and get the position + * of the keyblock. + */ +int +find_keyblock_byname( KBNODE *retblock, const char *username ) +{ + PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk ); + int rc; + + rc = get_pubkey_byname( NULL, pk, username, retblock ); + free_public_key(pk); + return rc; +} + + +/**************** + * Combined function to search for a key and get the position + * of the keyblock. Used for merging while importing keys. + */ +int +find_keyblock_bypk( KBNODE *retblock, PKT_public_key *pk ) +{ + char ufpr[50]; + + unified_fingerprint_from_pk( pk, ufpr, sizeof ufpr ); + return find_keyblock_byname( retblock, ufpr ); +} + +int +find_kblocation_bypk( void *re_opaque, PKT_public_key *pk ) +{ + PKT_public_key *dummy_pk = gcry_xcalloc( 1, sizeof *pk ); + char ufpr[50]; + GETKEY_CTX ctx; + int rc; + + unified_fingerprint_from_pk( pk, ufpr, sizeof ufpr ); + /* FIXME: There is no need to return any informaton, we just + * wnat to know the location. Using the general lookup function + * has the problem that we might not get the key becuase it has expired + * or due to some similar probelm. A solotion would be a locate-only + * flag in the ctx */ + rc = get_pubkey_byname( &ctx, dummy_pk, ufpr, NULL ); + free_public_key(dummy_pk); + if ( !rc ) + ringedit_copy_kbpos( re_opaque, &ctx->kbpos ); + get_pubkey_end( ctx ); + + return rc; +} + + /**************** * Search for a key with the given fingerprint. + * FIXME: + * We should replace this with the _byname function. Thiscsan be done + * by creating a userID conforming to the unified fingerprint style. */ int get_pubkey_byfprint( PKT_public_key *pk, @@ -988,19 +1077,23 @@ get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid ) * If NAME is NULL use the default key */ int -get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect ) +get_seckey_byname( GETKEY_CTX *retctx, + PKT_secret_key *sk, const char *name, int unprotect, + KBNODE *retblock ) { STRLIST namelist = NULL; int rc; if( !name && opt.def_secret_key && *opt.def_secret_key ) { add_to_strlist( &namelist, opt.def_secret_key ); - rc = key_byname( NULL, namelist, NULL, sk, NULL ); + rc = key_byname( retctx, namelist, NULL, sk, retblock ); } else if( !name ) { /* use the first one as default key */ struct getkey_ctx_s ctx; KBNODE kb = NULL; + assert (!retctx ); /* do we need this at all */ + assert (!retblock); memset( &ctx, 0, sizeof ctx ); ctx.not_allocated = 1; ctx.primary = 1; @@ -1014,7 +1107,7 @@ get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect ) } else { add_to_strlist( &namelist, name ); - rc = key_byname( NULL, namelist, NULL, sk, NULL ); + rc = key_byname( retctx, namelist, NULL, sk, retblock ); } free_strlist( namelist ); @@ -1045,6 +1138,7 @@ get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock ) return rc; } + void get_seckey_end( GETKEY_CTX ctx ) { @@ -1052,6 +1146,57 @@ get_seckey_end( GETKEY_CTX ctx ) } + +/**************** + * Combined function to search for a username and get the position + * of the keyblock. This function does not unprotect the secret key. + */ +int +find_secret_keyblock_byname( KBNODE *retblock, const char *username ) +{ + PKT_secret_key *sk = gcry_xcalloc( 1, sizeof *sk ); + int rc; + + rc = get_seckey_byname( NULL, sk, username, 0, retblock ); + free_secret_key(sk); + return rc; +} + + + +/**************** + * Combined function to search for a key and get the position + * of the keyblock. + */ +int +find_keyblock_bysk( KBNODE *retblock, PKT_secret_key *sk ) +{ + char ufpr[50]; + + unified_fingerprint_from_sk( sk, ufpr, sizeof ufpr ); + return find_secret_keyblock_byname( retblock, ufpr ); +} + +int +find_kblocation_bysk( void *re_opaque, PKT_secret_key *sk ) +{ + PKT_secret_key *dummy_sk = gcry_xcalloc( 1, sizeof *sk ); + char ufpr[50]; + GETKEY_CTX ctx; + int rc; + + unified_fingerprint_from_sk( sk, ufpr, sizeof ufpr ); + rc = get_seckey_byname( &ctx, dummy_sk, ufpr, 0, NULL ); + free_secret_key(dummy_sk); + if ( !rc ) + ringedit_copy_kbpos( re_opaque, &ctx->kbpos ); + get_seckey_end( ctx ); + + return rc; +} + + + /******************************************************* ************** compare functions ********************** @@ -1728,8 +1873,6 @@ void merge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) { KBNODE pub; - int deleting = 0; - int any_deleted = 0; assert ( pubblock->pkt->pkttype == PKT_PUBLIC_KEY ); assert ( secblock->pkt->pkttype == PKT_SECRET_KEY ); @@ -1750,7 +1893,6 @@ merge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) KBNODE sec; PKT_public_key *pk = pub->pkt->pkt.public_key; - deleting = 0; /* this is more complicated: it may happen that the sequence * of the subkeys dosn't match, so we have to find the * appropriate secret key */ @@ -1766,26 +1908,57 @@ merge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) } } } - if ( !sec ) { - log_error ( "no corresponding secret subkey " - "for public subkey - removing\n" ); - /* better remove the public subkey in this case */ - delete_kbnode ( pub ); - deleting = 1; - any_deleted = 1; - } - } - else if ( deleting ) { - delete_kbnode (pub); + if ( !sec ) + BUG(); /* already checked in premerge */ } } +} - if ( any_deleted ) { - /* because we have not deleted the root node, we don't need to - * update the pubblock */ - pub = pubblock; - commit_kbnode ( &pubblock ); - assert ( pub == pubblock ); +/* This function checks that for every public subkey a corresponding + * secret subkey is avalable and deletes the public subkey otherwise. + * We need this function becuase we can'tdelete it later when we + * actually merge the secret parts into the pubring. + */ +void +premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) +{ + KBNODE last, pub; + + assert ( pubblock->pkt->pkttype == PKT_PUBLIC_KEY ); + assert ( secblock->pkt->pkttype == PKT_SECRET_KEY ); + + for (pub=pubblock,last=NULL; pub; last = pub, pub = pub->next ) { + if ( pub->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { + KBNODE sec; + PKT_public_key *pk = pub->pkt->pkt.public_key; + + for (sec=secblock->next; sec; sec = sec->next ) { + if ( sec->pkt->pkttype == PKT_SECRET_SUBKEY ) { + PKT_secret_key *sk = sec->pkt->pkt.secret_key; + if ( !cmp_public_secret_key ( pk, sk ) ) + break; + } + } + if ( !sec ) { + KBNODE next, ll; + log_error ( "no corresponding secret subkey " + "for public subkey - removing\n" ); + /* we have to remove the subkey in this case */ + assert ( last ); + /* find the next subkey */ + for (next=pub->next,ll=pub; + next && pub->pkt->pkttype != PKT_PUBLIC_SUBKEY; + ll = next, next = next->next ) + ; + /* make new link */ + last->next = next; + /* release this public subkey with all sigs */ + ll->next = NULL; + release_kbnode( pub ); + /* let the loop continue */ + pub = last; + } + } } } @@ -1859,8 +2032,17 @@ find_by_fpr( KBNODE keyblock, const char *name, int mode ) size_t an; fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an ); - if( an == mode && !memcmp( afp, name, an) ) { - return k; + if ( mode == 21 ) { + /* Unified fingerprint. The fingerprint is always 20 bytes*/ + while ( an < 20 ) + afp[an++] = 0; + if ( !memcmp( afp, name, 20 ) ) + return k; + } + else { + if( an == mode && !memcmp( afp, name, an) ) { + return k; + } } } } @@ -2055,6 +2237,7 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode ) } secblock = ctx->keyblock; ctx->keyblock = k; + premerge_public_with_secret ( ctx->keyblock, secblock ); } @@ -2078,7 +2261,8 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode ) else if( item->mode == 15 ) { found = 1; } - else if( item->mode == 16 || item->mode == 20 ) { + else if( item->mode == 16 || item->mode == 20 + || item->mode == 21 ) { k = find_by_fpr( ctx->keyblock, item->fprint, item->mode ); found = !!k; @@ -2218,7 +2402,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys ) save_mode = set_packet_list_mode(0); init_packet(&pkt); - while( (rc=parse_packet(c->iobuf, &pkt)) != -1 ) { + while( (rc=parse_packet(c->iobuf, &pkt, NULL)) != -1 ) { if( rc ) ; /* e.g. unknown packet */ else if( pkt.pkttype == PKT_SECRET_KEY diff --git a/g10/import.c b/g10/import.c index 94b83f080..fa21fbc34 100644 --- a/g10/import.c +++ b/g10/import.c @@ -274,7 +274,7 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ) in_cert = 0; pkt = gcry_xmalloc( sizeof *pkt ); init_packet(pkt); - while( (rc=parse_packet(a, pkt)) != -1 ) { + while( (rc=parse_packet(a, pkt, NULL)) != -1 ) { if( rc ) { /* ignore errors */ if( rc != GPGERR_UNKNOWN_PACKET ) { log_error("read_block: read error: %s\n", gpg_errstr(rc) ); @@ -436,7 +436,7 @@ import_one( const char *fname, KBNODE keyblock, int fast ) if( (rc=lock_keyblock( &kbpos )) ) log_error(_("can't lock keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); - else if( (rc=insert_keyblock( &kbpos, keyblock )) ) + else if( (rc=insert_keyblock( keyblock )) ) log_error( _("error writing keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); unlock_keyblock( &kbpos ); @@ -466,18 +466,12 @@ import_one( const char *fname, KBNODE keyblock, int fast ) } /* now read the original keyblock */ - rc = find_keyblock_bypk( &kbpos, pk_orig ); + rc = find_keyblock_bypk( &keyblock_orig, pk_orig ); if( rc ) { log_error( _("key %08lX: can't locate original keyblock: %s\n"), (ulong)keyid[1], gpg_errstr(rc)); goto leave; } - rc = read_keyblock( &kbpos, &keyblock_orig ); - if( rc ) { - log_error( _("key %08lX: can't read original keyblock: %s\n"), - (ulong)keyid[1], gpg_errstr(rc)); - goto leave; - } collapse_uids( &keyblock ); /* and try to merge the block */ @@ -494,7 +488,7 @@ import_one( const char *fname, KBNODE keyblock, int fast ) if( (rc=lock_keyblock( &kbpos )) ) log_error( _("can't lock keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); - else if( (rc=update_keyblock( &kbpos, keyblock_orig )) ) + else if( (rc=update_keyblock( keyblock_orig )) ) log_error( _("error writing keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); unlock_keyblock( &kbpos ); @@ -603,7 +597,7 @@ import_secret_one( const char *fname, KBNODE keyblock ) if( (rc=lock_keyblock( &kbpos )) ) log_error( _("can't lock keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); - else if( (rc=insert_keyblock( &kbpos, keyblock )) ) + else if( (rc=insert_keyblock( keyblock )) ) log_error( _("error writing keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); unlock_keyblock( &kbpos ); @@ -659,18 +653,12 @@ import_revoke_cert( const char *fname, KBNODE node ) } /* read the original keyblock */ - rc = find_keyblock_bypk( &kbpos, pk ); + rc = find_keyblock_bypk( &keyblock, pk ); if( rc ) { log_error( _("key %08lX: can't locate original keyblock: %s\n"), (ulong)keyid[1], gpg_errstr(rc)); goto leave; } - rc = read_keyblock( &kbpos, &keyblock ); - if( rc ) { - log_error( _("key %08lX: can't read original keyblock: %s\n"), - (ulong)keyid[1], gpg_errstr(rc)); - goto leave; - } /* it is okay, that node is not in keyblock because @@ -704,7 +692,7 @@ import_revoke_cert( const char *fname, KBNODE node ) if( (rc=lock_keyblock( &kbpos )) ) log_error( _("can't lock keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); - else if( (rc=update_keyblock( &kbpos, keyblock )) ) + else if( (rc=update_keyblock( keyblock )) ) log_error( _("error writing keyring `%s': %s\n"), keyblock_resource_name(&kbpos), gpg_errstr(rc) ); unlock_keyblock( &kbpos ); diff --git a/g10/keydb.h b/g10/keydb.h index 43c36e719..95d369ed4 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -21,10 +21,6 @@ #ifndef GPG_KEYDB_H #define GPG_KEYDB_H -#ifdef HAVE_LIBGDBM - #include -#endif - #include "types.h" #include "basicdefs.h" #include "packet.h" @@ -67,30 +63,16 @@ struct kbnode_struct { enum resource_type { rt_UNKNOWN = 0, rt_RING = 1, - rt_GDBM = 2, - rt_KBXF = 3 + rt_KBXF = 2 }; /**************** - * A data structre to hold information about the external position + * A data structure to hold information about the external position * of a keyblock. */ -struct keyblock_pos_struct { - int resno; /* resource number */ - enum resource_type rt; - ulong offset; /* position information */ - unsigned count; /* length of the keyblock in packets */ - IOBUF fp; /* used by enum_keyblocks */ - int secret; /* working on a secret keyring */ - #ifdef HAVE_LIBGDBM - GDBM_FILE dbf; - byte keybuf[21]; - #endif - PACKET *pkt; /* ditto */ - int valid; -}; -typedef struct keyblock_pos_struct KBPOS; +struct keyblock_pos_struct; +typedef struct keyblock_pos_struct *KBPOS; /* structure to hold a couple of public key certificates */ struct pk_list { @@ -106,18 +88,6 @@ struct sk_list { int mark; }; -/* structure to collect all information which can be used to - * identify a public key */ -typedef struct pubkey_find_info *PUBKEY_FIND_INFO; -struct pubkey_find_info { - u32 keyid[2]; - unsigned nbits; - byte pubkey_algo; - byte fingerprint[MAX_FINGERPRINT_LEN]; - char userid[1]; -}; - - /*-- pkclist.c --*/ int check_signatures_trust( PKT_signature *sig ); @@ -159,11 +129,18 @@ int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint, size_t fprint_len ); int get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid ); int seckey_available( u32 *keyid ); -int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock ); +int get_seckey_byname( GETKEY_CTX *rx, + PKT_secret_key *sk, const char *name, int unlock, + KBNODE *retblock ); int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk, STRLIST names, KBNODE *ret_keyblock ); int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock ); void get_seckey_end( GETKEY_CTX ctx ); +int find_keyblock_byname( KBNODE *retblock, const char *username ); +int find_secret_keyblock_byname( KBNODE *retblock, const char *username ); +int find_keyblock_bypk( KBNODE *retblock, PKT_public_key *pk ); +int find_keyblock_bysk( KBNODE *retblock, PKT_secret_key *sk ); + int enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys ); void merge_keys_and_selfsig( KBNODE keyblock ); void merge_public_with_secret ( KBNODE pubblock, KBNODE secblock ); @@ -187,6 +164,10 @@ const char *expirestr_from_pk( PKT_public_key *pk ); const char *expirestr_from_sk( PKT_secret_key *sk ); byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len ); byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len ); +char *unified_fingerprint_from_pk( PKT_public_key *pk, + char *buffer, size_t bufsize ); +char *unified_fingerprint_from_sk( PKT_secret_key *sk, + char *buffer, size_t bufsize ); /*-- kbnode.c --*/ KBNODE new_kbnode( PACKET *pkt ); @@ -208,25 +189,13 @@ void dump_kbnode( KBNODE node ); /*-- ringedit.c --*/ const char *enum_keyblock_resources( int *sequence, int secret ); int add_keyblock_resource( const char *resname, int force, int secret ); -const char *keyblock_resource_name( KBPOS *kbpos ); -int get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ); +const char *keyblock_resource_name( KBPOS kbpos ); +int get_keyblock_handle( const char *filename, int secret, KBPOS kbpos ); char *get_writable_keyblock_file( int secret ); -int locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, - int fprlen, int secret ); -int locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, - int shortkid, int secret ); -int find_keyblock( PUBKEY_FIND_INFO info, KBPOS *kbpos ); -int find_keyblock_byname( KBPOS *kbpos, const char *username ); -int find_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk ); -int find_keyblock_bysk( KBPOS *kbpos, PKT_secret_key *sk ); -int find_secret_keyblock_byname( KBPOS *kbpos, const char *username ); -int lock_keyblock( KBPOS *kbpos ); -void unlock_keyblock( KBPOS *kbpos ); -int read_keyblock( KBPOS *kbpos, KBNODE *ret_root ); -int enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ); -int insert_keyblock( KBPOS *kbpos, KBNODE root ); -int delete_keyblock( KBPOS *kbpos ); -int update_keyblock( KBPOS *kbpos, KBNODE root ); +int enum_keyblocks( int mode, KBPOS kbpos, KBNODE *ret_root ); +int insert_keyblock( KBNODE keyblock ); +int delete_keyblock( KBNODE keyblock ); +int update_keyblock( KBNODE keyblock ); #endif /*GPG_KEYDB_H*/ diff --git a/g10/keyedit.c b/g10/keyedit.c index b7e836711..095e43baf 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -89,18 +89,13 @@ get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username ) *keyblock = NULL; /* search the userid */ - rc = find_keyblock_byname( kbpos, username ); + rc = find_keyblock_byname( keyblock, username ); if( rc ) { - log_error(_("%s: user not found\n"), username ); + log_error(_("%s: user not found: %s\n"), username, gpg_errstr(rc) ); return rc; } - /* read the keyblock */ - rc = read_keyblock( kbpos, keyblock ); - if( rc ) - log_error("%s: keyblock read problem: %s\n", username, gpg_errstr(rc)); - else - merge_keys_and_selfsig( *keyblock ); + merge_keys_and_selfsig( *keyblock ); return rc; } @@ -616,7 +611,6 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, KBNODE keyblock = NULL; KBPOS keyblockpos; KBNODE sec_keyblock = NULL; - KBPOS sec_keyblockpos; KBNODE cur_keyblock; char *answer = NULL; int redisplay = 1; @@ -640,14 +634,11 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, if( !sign_mode ) { /* first try to locate it as secret key */ - rc = find_secret_keyblock_byname( &sec_keyblockpos, username ); - if( !rc ) { - rc = read_keyblock( &sec_keyblockpos, &sec_keyblock ); - if( rc ) { - log_error("%s: secret keyblock read problem: %s\n", + rc = find_secret_keyblock_byname( &sec_keyblock, username ); + if( rc && rc != GPGERR_NO_SECKEY ) + log_debug("%s: secret keyblock read problem: %s\n", username, gpg_errstr(rc)); - goto leave; - } + if( !rc ) { merge_keys_and_selfsig( sec_keyblock ); if( fix_keyblock( sec_keyblock ) ) sec_modified++; @@ -966,14 +957,14 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, do_cmd_save: if( modified || sec_modified ) { if( modified ) { - rc = update_keyblock( &keyblockpos, keyblock ); + rc = update_keyblock( keyblock ); if( rc ) { log_error(_("update failed: %s\n"), gpg_errstr(rc) ); break; } } if( sec_modified ) { - rc = update_keyblock( &sec_keyblockpos, sec_keyblock ); + rc = update_keyblock( sec_keyblock ); if( rc ) { log_error(_("update secret failed: %s\n"), gpg_errstr(rc) ); diff --git a/g10/keygen.c b/g10/keygen.c index ef0064fc7..d3887dd7d 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1752,9 +1752,9 @@ do_generate_keypair( struct para_data_s *para, log_error("can't lock public keyring: %s\n", gpg_errstr(rc) ); else if( (rc=rc2=lock_keyblock( &sec_kbpos )) ) log_error("can't lock secret keyring: %s\n", gpg_errstr(rc) ); - else if( (rc=insert_keyblock( &pub_kbpos, pub_root )) ) + else if( (rc=insert_keyblock( pub_root )) ) log_error("can't write public key: %s\n", gpg_errstr(rc) ); - else if( (rc=insert_keyblock( &sec_kbpos, sec_root )) ) + else if( (rc=insert_keyblock( sec_root )) ) log_error("can't write secret key: %s\n", gpg_errstr(rc) ); else { if( !opt.batch ) diff --git a/g10/keyid.c b/g10/keyid.c index a4acb16d5..0269a6bb0 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -436,6 +436,40 @@ fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len ) return array; } + +/* Create a unified fingerprint, that is a printable fingerprint along + * wth some other information suitable to passto get_pubkye_byname. + * Pass NULL for buffer to let this function allocate the buffer. + * This function will truncate the buffer in a way that a valid C string + * is returnd (unless bufsize is 0) + * Returns: Supplied buffer or newly allocated buffer + */ +char * +unified_fingerprint_from_pk( PKT_public_key *pk, + char *buffer, size_t bufsize ) +{ + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; + int i; + + fingerprint_from_pk( pk, fpr, &fprlen ); + if ( !buffer ) { + bufsize = 1+fprlen*2+1+4+1+1; + buffer = gcry_xmalloc( bufsize ); + } + if ( bufsize < 1+fprlen*2+1+4+1+1 ) { + /* Hmmm, that should be sufficiend also not very nice */ + if ( bufsize ) + *buffer = 0; + return buffer; + } + *buffer = ':'; + for (i=0; i < fprlen; i++ ) + sprintf( buffer+1+i*2, "%02X", fpr[i] ); + sprintf( buffer+1+i*2, ":%d:", (pk->pubkey_algo & 0xff) ); + return buffer; +} + byte * fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len ) { @@ -495,5 +529,36 @@ fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len ) return array; } +char * +unified_fingerprint_from_sk( PKT_secret_key *sk, + char *buffer, size_t bufsize ) +{ + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; + int i; + + fingerprint_from_sk( sk, fpr, &fprlen ); + if ( !buffer ) { + bufsize = 1+fprlen*2+1+4+1+1; + buffer = gcry_xmalloc( bufsize ); + } + if ( bufsize < 1+fprlen*2+1+4+1+1 ) { + /* Hmmm, that should be sufficiend also not very nice */ + if ( bufsize ) + *buffer = 0; + return buffer; + } + *buffer = ':'; + for (i=0; i < fprlen; i++ ) + sprintf( buffer+1+i*2, "%02X", fpr[i] ); + sprintf( buffer+1+i*2, ":%d:", (sk->pubkey_algo & 0xff) ); + return buffer; +} + + + + + + diff --git a/g10/mainproc.c b/g10/mainproc.c index 09c35db21..7b04b3e6f 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -953,7 +953,7 @@ do_proc_packets( CTX c, IOBUF a ) c->iobuf = a; init_packet(pkt); - while( (rc=parse_packet(a, pkt)) != -1 ) { + while( (rc=parse_packet(a, pkt, NULL)) != -1 ) { any_data = 1; if( rc ) { free_packet(pkt); diff --git a/g10/packet.h b/g10/packet.h index 03fa2ca6e..33bcf792a 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -293,18 +293,19 @@ int set_packet_list_mode( int mode ); #if DEBUG_PARSE_PACKET int dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos, const char* file, int lineno ); -int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt, const char* file, int lineno ); +int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt, ulong *pos, + const char* file, int lineno ); int dbg_copy_all_packets( IOBUF inp, IOBUF out, const char* file, int lineno ); int dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff, const char* file, int lineno ); int dbg_skip_some_packets( IOBUF inp, unsigned n, const char* file, int lineno ); #define search_packet( a,b,c,d ) dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ ) -#define parse_packet( a, b ) dbg_parse_packet( (a), (b), __FILE__, __LINE__ ) +#define parse_packet( a, b, c ) dbg_parse_packet( (a), (b), (c), __FILE__, __LINE__ ) #define copy_all_packets( a,b ) dbg_copy_all_packets((a),(b), __FILE__, __LINE__ ) #define copy_some_packets( a,b,c ) dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ ) #define skip_some_packets( a,b ) dbg_skip_some_packets((a),(b), __FILE__, __LINE__ ) #else int search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos ); -int parse_packet( IOBUF inp, PACKET *ret_pkt); +int parse_packet( IOBUF inp, PACKET *ret_pkt, ulong *retpos); int copy_all_packets( IOBUF inp, IOBUF out ); int copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff ); int skip_some_packets( IOBUF inp, unsigned n ); diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 3cabe77b1..b22a59989 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -127,23 +127,25 @@ unknown_pubkey_warning( int algo ) */ #ifdef DEBUG_PARSE_PACKET int -dbg_parse_packet( IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l ) +dbg_parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos, + const char *dbg_f, int dbg_l ) { int skip, rc; do { - rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l ); + rc = parse( inp, pkt, 0, retpos, + &skip, NULL, 0, "parse", dbg_f, dbg_l ); } while( skip ); return rc; } #else int -parse_packet( IOBUF inp, PACKET *pkt ) +parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos ) { int skip, rc; do { - rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 ); + rc = parse( inp, pkt, 0, retpos, &skip, NULL, 0 ); } while( skip ); return rc; } diff --git a/g10/pkclist.c b/g10/pkclist.c index d585880ea..1170c4088 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -779,7 +779,7 @@ default_recipient(void) if( !opt.def_recipient_self ) return NULL; sk = gcry_xcalloc( 1, sizeof *sk ); - i = get_seckey_byname( sk, NULL, 0 ); + i = get_seckey_byname( NULL, sk, NULL, 0, NULL ); if( i ) { free_secret_key( sk ); return NULL; diff --git a/g10/revoke.c b/g10/revoke.c index 4abd5edd7..e988e5e62 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -87,7 +87,6 @@ gen_revoke( const char *uname ) IOBUF out = NULL; KBNODE keyblock = NULL; KBNODE node; - KBPOS kbpos; struct revocation_reason_info *reason = NULL; if( opt.batch ) { @@ -102,16 +101,10 @@ gen_revoke( const char *uname ) /* search the userid */ - rc = find_secret_keyblock_byname( &kbpos, uname ); + rc = find_secret_keyblock_byname( &keyblock, uname ); if( rc ) { - log_error(_("secret key for user `%s' not found\n"), uname ); - goto leave; - } - - /* read the keyblock */ - rc = read_keyblock( &kbpos, &keyblock ); - if( rc ) { - log_error(_("error reading the certificate: %s\n"), gpg_errstr(rc) ); + log_error(_("secret key for user `%s' not found: %s\n"), + uname, gpg_errstr(rc) ); goto leave; } diff --git a/g10/ringedit.c b/g10/ringedit.c index 311cf41fc..de05ba6e2 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -48,9 +48,6 @@ #include #include /* for truncate */ #include -#ifdef HAVE_LIBGDBM - #include -#endif #include #include "util.h" @@ -71,47 +68,42 @@ struct resource_table_struct { int secret; /* this is a secret keyring */ char *fname; IOBUF iobuf; - #ifdef HAVE_LIBGDBM - GDBM_FILE dbf; - #endif enum resource_type rt; DOTLOCK lockhd; int is_locked; }; typedef struct resource_table_struct RESTBL; + +struct keyblock_pos_struct { + int resno; /* resource number */ + enum resource_type rt; + ulong offset; /* position information */ + unsigned count; /* length of the keyblock in packets */ + IOBUF fp; /* used by enum_keyblocks */ + int secret; /* working on a secret keyring */ + PACKET *pkt; /* ditto */ + int valid; + ulong save_offset; +}; + + + + #define MAX_RESOURCES 10 static RESTBL resource_table[MAX_RESOURCES]; static int default_public_resource; static int default_secret_resource; -static int search( PACKET *pkt, KBPOS *kbpos, int secret ); +static int keyring_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs ); +static int keyring_copy( KBPOS kbpos, int mode, KBNODE root ); - -static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf, - const char *fname ); -static int keyring_read( KBPOS *kbpos, KBNODE *ret_root ); -static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ); -static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root ); - -static int do_kbxf_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf, - const char *fname ); -static int do_kbxf_read( KBPOS *kbpos, KBNODE *ret_root ); -static int do_kbxf_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ); -static int do_kbxf_copy( KBPOS *kbpos, int mode, KBNODE root ); - -#ifdef HAVE_LIBGDBM -static int do_gdbm_store( KBPOS *kbpos, KBNODE root, int update ); -static int do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, - const byte *fpr, int fprlen ); -static int do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid ); -static int do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ); -static int do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root ); -#endif +static int do_kbxf_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs ); +static int do_kbxf_copy( KBPOS kbpos, int mode, KBNODE root ); static RESTBL * -check_pos( KBPOS *kbpos ) +check_pos( KBPOS kbpos ) { if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES ) return NULL; @@ -120,15 +112,6 @@ check_pos( KBPOS *kbpos ) return resource_table + kbpos->resno; } -#ifdef HAVE_LIBGDBM -static void -fatal_gdbm_error( const char *string ) -{ - log_fatal("gdbm failed: %s\n", string); -} - -#endif /* HAVE_LIBGDBM */ - /**************** * Hmmm, how to avoid deadlock? They should not happen if everyone @@ -208,7 +191,6 @@ add_keyblock_resource( const char *url, int force, int secret ) /* Do we have an URL? - * gnupg-gdbm:filename := this is a GDBM resource * gnupg-kbxf:filename := this is a KBX file resource * gnupg-ring:filename := this is a plain keyring * filename := See what is is, but create as plain keyring. @@ -222,10 +204,6 @@ add_keyblock_resource( const char *url, int force, int secret ) rt = rt_KBXF; resname += 11; } - else if( !strncmp( resname, "gnupg-gdbm:", 11 ) ) { - rt = rt_GDBM; - resname += 11; - } #ifndef HAVE_DRIVE_LETTERS else if( strchr( resname, ':' ) ) { log_error("%s: invalid URL\n", url ); @@ -263,22 +241,16 @@ add_keyblock_resource( const char *url, int force, int secret ) u32 magic; if( fread( &magic, 4, 1, fp) == 1 ) { - if( magic == 0x13579ace ) - rt = rt_GDBM; - else if( magic == 0xce9a5713 ) - log_error("%s: endianess does not match\n", url ); - else { - char buf[8]; + char buf[8]; - rt = rt_RING; - if( fread( buf, 8, 1, fp) == 1 ) { - if( !memcmp( buf+4, "KBXf", 4 ) - && buf[0] == 1 && buf[1] == 1 ) { - rt = rt_KBXF; - } - } - } - } + rt = rt_RING; + if( fread( buf, 8, 1, fp) == 1 ) { + if( !memcmp( buf+4, "KBXf", 4 ) + && buf[0] == 1 && buf[1] == 1 ) { + rt = rt_KBXF; + } + } + } else /* maybe empty: assume ring */ rt = rt_RING; fclose( fp ); @@ -348,21 +320,6 @@ add_keyblock_resource( const char *url, int force, int secret ) #endif break; - #ifdef HAVE_LIBGDBM - case rt_GDBM: - resource_table[i].dbf = gdbm_open( filename, 0, - force? GDBM_WRCREAT : GDBM_WRITER, - S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP | S_IROTH, - fatal_gdbm_error ); - if( !resource_table[i].dbf ) { - log_error("%s: can't open gdbm file: %s\n", - filename, gdbm_strerror(gdbm_errno)); - rc = GPGERR_OPEN_FILE; - goto leave; - } - break; - #endif default: log_error("%s: unsupported resource type\n", url ); @@ -403,7 +360,7 @@ add_keyblock_resource( const char *url, int force, int secret ) * Return the resource name of the keyblock associated with KBPOS. */ const char * -keyblock_resource_name( KBPOS *kbpos ) +keyblock_resource_name( KBPOS kbpos ) { RESTBL *rentry; @@ -419,7 +376,7 @@ keyblock_resource_name( KBPOS *kbpos ) * Using a filename of NULL returns the default resource */ int -get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ) +get_keyblock_handle( const char *filename, int secret, KBPOS kbpos ) { int i = 0; @@ -471,253 +428,21 @@ get_writable_keyblock_file( int secret ) } -/**************** - * Search a keyblock which starts with the given packet and puts all - * information into KBPOS, which can be used later to access this key block. - * This function looks into all registered keyblock sources. - * PACKET must be a packet with either a secret_key or a public_key - * - * This function is intended to check whether a given certificate - * is already in a keyring or to prepare it for editing. - * - * Returns: 0 if found, -1 if not found or an errorcode. - */ -static int -search( PACKET *pkt, KBPOS *kbpos, int secret ) +void +ringedit_copy_kbpos ( KBPOS d, KBPOS s ) { - int i, rc, last_rc=-1; - - for(i=0; i < MAX_RESOURCES; i++ ) { - if( resource_table[i].used && !resource_table[i].secret == !secret ) { - switch( resource_table[i].rt ) { - case rt_RING: - rc = keyring_search( pkt, kbpos, resource_table[i].iobuf, - resource_table[i].fname ); - break; - case rt_KBXF: - rc = do_kbxf_search( pkt, kbpos, resource_table[i].iobuf, - resource_table[i].fname ); - break; - #ifdef HAVE_LIBGDBM - case rt_GDBM: { - PKT_public_key *req_pk = pkt->pkt.public_key; - byte fpr[20]; - size_t fprlen; - - fingerprint_from_pk( req_pk, fpr, &fprlen ); - rc = do_gdbm_locate( resource_table[i].dbf, - kbpos, fpr, fprlen ); - } - break; - #endif - default: BUG(); - } - - kbpos->rt = resource_table[i].rt; - if( !rc ) { - kbpos->resno = i; - kbpos->fp = NULL; - return 0; - } - if( rc != -1 ) { - log_error("error searching resource %d: %s\n", - i, gpg_errstr(rc)); - last_rc = rc; - } - } - } - return last_rc; + *d = *s; } -/**************** - * Combined function to search for a username and get the position - * of the keyblock. - */ -int -find_keyblock_byname( KBPOS *kbpos, const char *username ) -{ - PACKET pkt; - PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk ); - int rc; - - rc = get_pubkey_byname( NULL, pk, username, NULL ); - if( rc ) { - free_public_key(pk); - return rc; - } - - init_packet( &pkt ); - pkt.pkttype = PKT_PUBLIC_KEY; - pkt.pkt.public_key = pk; - rc = search( &pkt, kbpos, 0 ); - free_public_key(pk); - return rc; -} - - -/**************** - * Combined function to search for a key and get the position - * of the keyblock. - */ -int -find_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk ) -{ - PACKET pkt; - int rc; - - init_packet( &pkt ); - pkt.pkttype = PKT_PUBLIC_KEY; - pkt.pkt.public_key = pk; - rc = search( &pkt, kbpos, 0 ); - return rc; -} - -/**************** - * Combined function to search for a key and get the position - * of the keyblock. - */ -int -find_keyblock_bysk( KBPOS *kbpos, PKT_secret_key *sk ) -{ - PACKET pkt; - int rc; - - init_packet( &pkt ); - pkt.pkttype = PKT_SECRET_KEY; - pkt.pkt.secret_key = sk; - rc = search( &pkt, kbpos, 0 ); - return rc; -} - - -/**************** - * Combined function to search for a username and get the position - * of the keyblock. This function does not unprotect the secret key. - */ -int -find_secret_keyblock_byname( KBPOS *kbpos, const char *username ) -{ - PACKET pkt; - PKT_secret_key *sk = gcry_xcalloc( 1, sizeof *sk ); - int rc; - - rc = get_seckey_byname( sk, username, 0 ); - if( rc ) { - free_secret_key(sk); - return rc; - } - - init_packet( &pkt ); - pkt.pkttype = PKT_SECRET_KEY; - pkt.pkt.secret_key = sk; - rc = search( &pkt, kbpos, 1 ); - free_secret_key(sk); - return rc; -} - - -/**************** - * Locate a keyblock in a database which is capable of direct access - * Put all information into KBPOS, which can be later be to access this - * key block. - * This function looks into all registered keyblock sources. - * - * Returns: 0 if found, - * -1 if not found - * GPGERR_UNSUPPORTED if no resource is able to handle this - * or another errorcode. - */ -int -locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret ) -{ - RESTBL *rentry; - int i, rc, any=0, last_rc=-1; - - - for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) { - if( rentry->used && !rentry->secret == !secret ) { - kbpos->rt = rentry->rt; - switch( rentry->rt ) { - #ifdef HAVE_LIBGDBM - case rt_GDBM: - any = 1; - rc = do_gdbm_locate( rentry->dbf, kbpos, fpr, fprlen ); - break; - #endif - default: - rc = GPGERR_UNSUPPORTED; - break; - } - - if( !rc ) { - kbpos->resno = i; - kbpos->fp = NULL; - return 0; - } - else if( rc != -1 && rc != GPGERR_UNSUPPORTED ) { - log_error("error searching resource %d: %s\n", - i, gpg_errstr(rc)); - last_rc = rc; - } - } - } - - return (last_rc == -1 && !any)? GPGERR_UNSUPPORTED : last_rc; -} - - -int -locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, int shortkid, int secret ) -{ - RESTBL *rentry; - int i, rc, any=0, last_rc=-1; - - if( shortkid ) - return GPGERR_UNSUPPORTED; - - for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) { - if( rentry->used && !rentry->secret == !secret ) { - kbpos->rt = rentry->rt; - switch( rentry->rt ) { - #ifdef HAVE_LIBGDBM - case rt_GDBM: - any = 1; - rc = do_gdbm_locate_by_keyid( rentry->dbf, kbpos, keyid ); - break; - #endif - default: - rc = GPGERR_UNSUPPORTED; - break; - } - - if( !rc ) { - kbpos->resno = i; - kbpos->fp = NULL; - return 0; - } - else if( rc != -1 && rc != GPGERR_UNSUPPORTED ) { - log_error("error searching resource %d: %s\n", - i, gpg_errstr(rc)); - last_rc = rc; - } - } - } - - return (last_rc == -1 && !any)? GPGERR_UNSUPPORTED : last_rc; -} - - - - /**************** * Lock the keyblock; wait until it's available * This function may change the internal data in kbpos, in cases * when the keyblock to be locked has been modified. * fixme: remove this function and add an option to search()? */ -int -lock_keyblock( KBPOS *kbpos ) +static int +lock_keyblock( KBPOS kbpos ) { if( !check_pos(kbpos) ) return GPGERR_GENERAL; @@ -727,35 +452,13 @@ lock_keyblock( KBPOS *kbpos ) /**************** * Release a lock on a keyblock */ -void -unlock_keyblock( KBPOS *kbpos ) +static void +unlock_keyblock( KBPOS kbpos ) { if( !check_pos(kbpos) ) BUG(); } -/**************** - * Read a complete keyblock and return the root in ret_root. - */ -int -read_keyblock( KBPOS *kbpos, KBNODE *ret_root ) -{ - if( !check_pos(kbpos) ) - return GPGERR_GENERAL; - - switch( kbpos->rt ) { - case rt_RING: - return keyring_read( kbpos, ret_root ); - case rt_KBXF: - return do_kbxf_read( kbpos, ret_root ); - #ifdef HAVE_LIBGDBM - case rt_GDBM: - return do_gdbm_read( kbpos, ret_root ); - #endif - default: BUG(); - } -} - /**************** * This functions can be used to read through a complete keyring. @@ -765,13 +468,9 @@ read_keyblock( KBPOS *kbpos, KBNODE *ret_root ) * 5 = open secret keyrings * 11 = read but skip signature and comment packets. * all others are reserved! - * Note that you do not need a search prior to this function, - * only a handle is needed. - * NOTE: It is not allowed to do an insert/update/delete with this - * keyblock, if you want to do this, use search/read! */ int -enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) +enum_keyblocks( int mode, KBPOS kbpos, KBNODE *ret_root ) { int rc = 0; RESTBL *rentry; @@ -811,12 +510,7 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) return GPGERR_OPEN_FILE; } break; - #ifdef HAVE_LIBGDBM - case rt_GDBM: - /* FIXME: make sure that there is only one enum at a time */ - kbpos->offset = 0; - break; - #endif + default: BUG(); } kbpos->pkt = NULL; @@ -836,11 +530,6 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) return GPGERR_GENERAL; rc = do_kbxf_enum( kbpos, ret_root, mode == 11 ); break; - #ifdef HAVE_LIBGDBM - case rt_GDBM: - rc = do_gdbm_enum( kbpos, ret_root ); - break; - #endif default: BUG(); } @@ -866,8 +555,6 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) kbpos->fp = NULL; } break; - case rt_GDBM: - break; case rt_UNKNOWN: /* this happens when we have no keyring at all */ return rc; @@ -890,10 +577,10 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root ) * by KBPOS. This actually appends the data to the keyfile. */ int -insert_keyblock( KBPOS *kbpos, KBNODE root ) +insert_keyblock( KBNODE root ) { int rc; - +#if 0 if( !check_pos(kbpos) ) return GPGERR_GENERAL; @@ -904,14 +591,9 @@ insert_keyblock( KBPOS *kbpos, KBNODE root ) case rt_KBXF: rc = do_kbxf_copy( kbpos, 1, root ); break; - #ifdef HAVE_LIBGDBM - case rt_GDBM: - rc = do_gdbm_store( kbpos, root, 0 ); - break; - #endif default: BUG(); } - +#endif return rc; } @@ -922,10 +604,10 @@ insert_keyblock( KBPOS *kbpos, KBNODE root ) * zero bytes are written. */ int -delete_keyblock( KBPOS *kbpos ) +delete_keyblock( KBNODE keyblock ) { int rc; - + #if 0 if( !check_pos(kbpos) ) return GPGERR_GENERAL; @@ -936,42 +618,43 @@ delete_keyblock( KBPOS *kbpos ) case rt_KBXF: rc = do_kbxf_copy( kbpos, 2, NULL ); break; - #ifdef HAVE_LIBGDBM - case rt_GDBM: - log_debug("deleting gdbm keyblock is not yet implemented\n"); - rc = 0; - break; - #endif default: BUG(); } - + #endif return rc; } /**************** - * Update the keyblock at KBPOS with the one in ROOT. + * Update the keyblock in the ring (or whatever resource) one in ROOT. */ int -update_keyblock( KBPOS *kbpos, KBNODE root ) +update_keyblock( KBNODE root ) { int rc; + struct WORK WORK WORK KBPOS kbpos; + + /* We need to get the file position of original keyblock first */ + if ( root->pkt->pkttype == PKT_PUBLIC_KEY ) + rc = find_kblocation_bypk( &kbpos, root->pkt->pkt.public_key ); + else if ( root->pkt->pkttype == PKT_SECRET_KEY ) + rc = find_kblocation_bysk( &kbpos, root->pkt->pkt.secret_key ); + else + BUG(); - if( !check_pos(kbpos) ) + if ( rc ) + return rc; + + if( !check_pos(&kbpos) ) return GPGERR_GENERAL; - switch( kbpos->rt ) { + switch( kbpos.rt ) { case rt_RING: - rc = keyring_copy( kbpos, 3, root ); + rc = keyring_copy( &kbpos, 3, root ); break; case rt_KBXF: - rc = do_kbxf_copy( kbpos, 3, root ); + rc = do_kbxf_copy( &kbpos, 3, root ); break; - #ifdef HAVE_LIBGDBM - case rt_GDBM: - rc = do_gdbm_store( kbpos, root, 1 ); - break; - #endif default: BUG(); } @@ -979,321 +662,11 @@ update_keyblock( KBPOS *kbpos, KBNODE root ) } - -/**************************************************************** - ********** Implemenation of a user ID database ************** - ****************************************************************/ -#if 0 -/**************** - * Layout of the user ID db - * - * This user ID DB provides fast lookup of user ID, but the user ids are - * not in any specific order. - * - * A string "GnuPG user db", a \n. - * user ids of one key, delimited by \t, - * a # or ^ followed by a 20 byte fingerprint, followed by an \n - * The literal characters %, \n, \t, #, ^ must be replaced by a percent sign - * and their hex value. - * - * (We use Boyer/Moore pattern matching) - */ - -/**************** - * This compiles pattern to the distance table, the table will be allocate - * here and must be freed by using free(). - * Returns: Ptr to new allocated Table - * Caller must free the table. - */ - -static size_t * -compile_bm_table( const byte *pattern, size_t len ) -{ - ushort *dist; - int i; - - dist = gcry_xcalloc( 1, 256 * sizeof *dist ); - for(i=0; i < 256; i++ ) - dist[i] = len; - for(i=0; i < len-1; i++ ) - dTbl[p[i]] = len-i-1; - return dist; -} - - - - -/**************** - * Search BUF of BUFLEN for pattern P of length PATLEN. - * dist is the Boyer/Moore distance table of 256 Elements, - * case insensitive search is done if IGNCASE is true (In this case - * the distance table has to compiled from uppercase chacaters and - * PAT must also be uppercase. - * Returns: Prt to maching string in BUF, or NULL if not found. - */ - -static const * -do_bm_search( const byte *buf, size_t buflen, - const byte *pat, size_t patlen, size_t *dist, int igncase ) -{ - int i, j, k; - - if( igncase ) { - int c, c1; - - for( i = --patlen; i < buflen; i += dist[c1] ) - for( j=patlen, k=i, c1=c=toupper(buf[k]); c == pat[j]; - j--, k--, c=toupper(buf[k]) ) { - if( !j ) - return buf+k; - } - } - else { - for( i = --patlen; i < buflen; i += dist[buf[i]] ) - for( j=patlen, k=i; buf[k] == pat[j]; j--, k-- ) { - if( !j ) - return buf+k; - } - } - return NULL; -} - - -typedef struct { - size_t dist[256]; -} *SCAN_USER_HANDLE; - -static SCAN_USER_HANDLE -scan_user_file_open( const byte *name ) -{ - SCAN_USER_HANDLE hd; - size_t *dist; - int i; - - hd = gcry_xcalloc( 1, sizeof *hd ); - dist = hd->dist; - /* compile the distance table */ - for(i=0; i < 256; i++ ) - dist[i] = len; - for(i=0; i < len-1; i++ ) - dTbl[p[i]] = len-i-1; - /* setup other things */ - - return hd; -} - -static int -scan_user_file_close( SCAN_USER_HANDLE hd ) -{ - gcry_free( hd ); -} - -static int -scan_user_file_read( SCAN_USER_HANDLE hd, byte *fpr ) -{ - char record[1000]; - - /* read a record */ - - -} -#endif - - /**************************************************************** ********** Functions which operates on regular keyrings ******** ****************************************************************/ -static int -cmp_seckey( PKT_secret_key *req_sk, PKT_secret_key *sk ) -{ - int n,i; - - assert( req_sk->pubkey_algo == sk->pubkey_algo ); - - n = pubkey_get_nskey( req_sk->pubkey_algo ); - for(i=0; i < n; i++ ) { - /* Note: because v4 protected keys have nothing in the - * mpis except for the first one, we skip all NULL MPIs. - * This might not be always correct in cases where the both - * keys do not match in their secret parts but we can ignore that - * because the need for this function is quite ugly. */ - if( req_sk->skey[1] && sk->skey[i] - && mpi_cmp( req_sk->skey[i], sk->skey[i] ) ) - return -1; - } - return 0; -} - -static int -cmp_pubkey( PKT_public_key *req_pk, PKT_public_key *pk ) -{ - int n, i; - - assert( req_pk->pubkey_algo == pk->pubkey_algo ); - - n = pubkey_get_npkey( req_pk->pubkey_algo ); - for(i=0; i < n; i++ ) { - if( mpi_cmp( req_pk->pkey[i], pk->pkey[i] ) ) - return -1; - } - return 0; -} - -/**************** - * search one keyring, return 0 if found, -1 if not found or an errorcode. - */ -static int -keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname ) -{ - int rc; - PACKET pkt; - int save_mode; - ulong offset; - int pkttype = req->pkttype; - PKT_public_key *req_pk = req->pkt.public_key; - PKT_secret_key *req_sk = req->pkt.secret_key; - - init_packet(&pkt); - save_mode = set_packet_list_mode(0); - kbpos->rt = rt_RING; - kbpos->valid = 0; - - #if HAVE_DOSISH_SYSTEM || 1 - assert(!iobuf); - iobuf = iobuf_open( fname ); - if( !iobuf ) { - log_error("%s: can't open keyring file\n", fname); - rc = GPGERR_KEYRING_OPEN; - goto leave; - } - #else - if( iobuf_seek( iobuf, 0 ) ) { - log_error("can't rewind keyring file\n"); - rc = GPGERR_KEYRING_OPEN; - goto leave; - } - #endif - - while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) { - if( pkt.pkttype == PKT_SECRET_KEY ) { - PKT_secret_key *sk = pkt.pkt.secret_key; - - if( req_sk->timestamp == sk->timestamp - && req_sk->pubkey_algo == sk->pubkey_algo - && !cmp_seckey( req_sk, sk) ) - break; /* found */ - } - else if( pkt.pkttype == PKT_PUBLIC_KEY ) { - PKT_public_key *pk = pkt.pkt.public_key; - - if( req_pk->timestamp == pk->timestamp - && req_pk->pubkey_algo == pk->pubkey_algo - && !cmp_pubkey( req_pk, pk ) ) - break; /* found */ - } - else - BUG(); - free_packet(&pkt); - } - if( !rc ) { - kbpos->offset = offset; - kbpos->valid = 1; - } - - leave: - free_packet(&pkt); - set_packet_list_mode(save_mode); - #if HAVE_DOSISH_SYSTEM || 1 - iobuf_close(iobuf); - #endif - return rc; -} - - -static int -keyring_read( KBPOS *kbpos, KBNODE *ret_root ) -{ - PACKET *pkt; - int rc; - RESTBL *rentry; - KBNODE root = NULL; - IOBUF a; - int in_cert = 0; - - if( !(rentry=check_pos(kbpos)) ) - return GPGERR_GENERAL; - - a = iobuf_open( rentry->fname ); - if( !a ) { - log_error("can't open `%s'\n", rentry->fname ); - return GPGERR_OPEN_FILE; - } - - if( !kbpos->valid ) - log_debug("kbpos not valid in keyring_read, want %d\n", (int)kbpos->offset ); - if( iobuf_seek( a, kbpos->offset ) ) { - log_error("can't seek to %lu\n", kbpos->offset); - iobuf_close(a); - return GPGERR_KEYRING_OPEN; - } - - pkt = gcry_xmalloc( sizeof *pkt ); - init_packet(pkt); - kbpos->count=0; - while( (rc=parse_packet(a, pkt)) != -1 ) { - if( rc ) { /* ignore errors */ - if( rc != GPGERR_UNKNOWN_PACKET ) { - log_error("read_keyblock: read error: %s\n", gpg_errstr(rc) ); - rc = GPGERR_INV_KEYRING; - goto ready; - } - kbpos->count++; - free_packet( pkt ); - init_packet( pkt ); - continue; - } - /* make a linked list of all packets */ - switch( pkt->pkttype ) { - case PKT_COMPRESSED: - log_error("skipped compressed packet in keyring\n" ); - free_packet(pkt); - init_packet(pkt); - break; - - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - if( in_cert ) - goto ready; - in_cert = 1; - default: - kbpos->count++; - if( !root ) - root = new_kbnode( pkt ); - else - add_kbnode( root, new_kbnode( pkt ) ); - pkt = gcry_xmalloc( sizeof *pkt ); - init_packet(pkt); - break; - } - } - ready: - kbpos->valid = 0; - if( rc == -1 && root ) - rc = 0; - - if( rc ) - release_kbnode( root ); - else - *ret_root = root; - free_packet( pkt ); - gcry_free( pkt ); - iobuf_close(a); - return rc; -} - - static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) { @@ -1301,21 +674,24 @@ keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) int rc; RESTBL *rentry; KBNODE root = NULL; + ulong offset, first_offset=0; if( !(rentry=check_pos(kbpos)) ) return GPGERR_GENERAL; if( kbpos->pkt ) { root = new_kbnode( kbpos->pkt ); + first_offset = kbpos->save_offset; kbpos->pkt = NULL; } + kbpos->valid = 0; pkt = gcry_xmalloc( sizeof *pkt ); init_packet(pkt); - while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) { + while( (rc=parse_packet(kbpos->fp, pkt, &offset )) != -1 ) { if( rc ) { /* ignore errors */ if( rc != GPGERR_UNKNOWN_PACKET ) { - log_error("read_keyblock: read error: %s\n", gpg_errstr(rc) ); + log_error("keyring_enum: read error: %s\n", gpg_errstr(rc) ); rc = GPGERR_INV_KEYRING; goto ready; } @@ -1333,12 +709,14 @@ keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: - if( root ) { /* store this packet */ + if( root ) { /* save this packet */ kbpos->pkt = pkt; + kbpos->save_offset = offset; pkt = NULL; goto ready; } root = new_kbnode( pkt ); + first_offset = offset; pkt = gcry_xmalloc( sizeof *pkt ); init_packet(pkt); break; @@ -1368,8 +746,13 @@ keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) if( rc ) release_kbnode( root ); - else + else { + if ( root ) { + kbpos->offset = first_offset; + kbpos->valid = 1; + } *ret_root = root; + } free_packet( pkt ); gcry_free( pkt ); @@ -1391,11 +774,11 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) int rc=0; char *bakfname = NULL; char *tmpfname = NULL; +#warning We need to lock the keyring while we are editing it. + /* rethink this whole module */ if( !(rentry = check_pos( kbpos )) ) return GPGERR_GENERAL; - if( kbpos->fp ) - BUG(); /* not allowed with such a handle */ if( opt.dry_run ) return 0; @@ -1403,6 +786,13 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) lock_rentry( rentry ); /* open the source file */ + if( kbpos->fp ) { + /* BUG(); not allowed with such a handle */ + log_debug("keyring_copy: closing fp %p\n", kbpos->fp ); + iobuf_close (kbpos->fp); + kbpos->fp = NULL; + kbpos->valid = 0; + } fp = iobuf_open( rentry->fname ); if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */ KBNODE kbctx, node; @@ -1612,159 +1002,6 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root ) ********** Functions which operate on KBX files **************** ****************************************************************/ -/**************** - * search a KBX file return 0 if found, -1 if not found or an errorcode. - */ -static int -do_kbxf_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname ) -{ - int rc; - PACKET pkt; - int save_mode; - ulong offset; - int pkttype = req->pkttype; - PKT_public_key *req_pk = req->pkt.public_key; - PKT_secret_key *req_sk = req->pkt.secret_key; - - init_packet(&pkt); - save_mode = set_packet_list_mode(0); - kbpos->rt = rt_RING; - kbpos->valid = 0; - - #if HAVE_DOSISH_SYSTEM || 1 - assert(!iobuf); - iobuf = iobuf_open( fname ); - if( !iobuf ) { - log_error("%s: can't open keyring file\n", fname); - rc = GPGERR_KEYRING_OPEN; - goto leave; - } - #else - if( iobuf_seek( iobuf, 0 ) ) { - log_error("can't rewind keyring file\n"); - rc = GPGERR_KEYRING_OPEN; - goto leave; - } - #endif - - while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) { - if( pkt.pkttype == PKT_SECRET_KEY ) { - PKT_secret_key *sk = pkt.pkt.secret_key; - - if( req_sk->timestamp == sk->timestamp - && req_sk->pubkey_algo == sk->pubkey_algo - && !cmp_seckey( req_sk, sk) ) - break; /* found */ - } - else if( pkt.pkttype == PKT_PUBLIC_KEY ) { - PKT_public_key *pk = pkt.pkt.public_key; - - if( req_pk->timestamp == pk->timestamp - && req_pk->pubkey_algo == pk->pubkey_algo - && !cmp_pubkey( req_pk, pk ) ) - break; /* found */ - } - else - BUG(); - free_packet(&pkt); - } - if( !rc ) { - kbpos->offset = offset; - kbpos->valid = 1; - } - - leave: - free_packet(&pkt); - set_packet_list_mode(save_mode); - #if HAVE_DOSISH_SYSTEM || 1 - iobuf_close(iobuf); - #endif - return rc; -} - - -static int -do_kbxf_read( KBPOS *kbpos, KBNODE *ret_root ) -{ - PACKET *pkt; - int rc; - RESTBL *rentry; - KBNODE root = NULL; - IOBUF a; - int in_cert = 0; - - if( !(rentry=check_pos(kbpos)) ) - return GPGERR_GENERAL; - - a = iobuf_open( rentry->fname ); - if( !a ) { - log_error("can't open `%s'\n", rentry->fname ); - return GPGERR_OPEN_FILE; - } - - if( !kbpos->valid ) - log_debug("kbpos not valid in keyring_read, want %d\n", (int)kbpos->offset ); - if( iobuf_seek( a, kbpos->offset ) ) { - log_error("can't seek to %lu\n", kbpos->offset); - iobuf_close(a); - return GPGERR_KEYRING_OPEN; - } - - pkt = gcry_xmalloc( sizeof *pkt ); - init_packet(pkt); - kbpos->count=0; - while( (rc=parse_packet(a, pkt)) != -1 ) { - if( rc ) { /* ignore errors */ - if( rc != GPGERR_UNKNOWN_PACKET ) { - log_error("read_keyblock: read error: %s\n", gpg_errstr(rc) ); - rc = GPGERR_INV_KEYRING; - goto ready; - } - kbpos->count++; - free_packet( pkt ); - init_packet( pkt ); - continue; - } - /* make a linked list of all packets */ - switch( pkt->pkttype ) { - case PKT_COMPRESSED: - log_error("skipped compressed packet in keyring\n" ); - free_packet(pkt); - init_packet(pkt); - break; - - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - if( in_cert ) - goto ready; - in_cert = 1; - default: - kbpos->count++; - if( !root ) - root = new_kbnode( pkt ); - else - add_kbnode( root, new_kbnode( pkt ) ); - pkt = gcry_xmalloc( sizeof *pkt ); - init_packet(pkt); - break; - } - } - ready: - kbpos->valid = 0; - if( rc == -1 && root ) - rc = 0; - - if( rc ) - release_kbnode( root ); - else - *ret_root = root; - free_packet( pkt ); - gcry_free( pkt ); - iobuf_close(a); - return rc; -} - - static int do_kbxf_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) { @@ -1783,10 +1020,10 @@ do_kbxf_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) pkt = gcry_xmalloc( sizeof *pkt ); init_packet(pkt); - while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) { + while( (rc=parse_packet(kbpos->fp, pkt, NULL)) != -1 ) { if( rc ) { /* ignore errors */ if( rc != GPGERR_UNKNOWN_PACKET ) { - log_error("read_keyblock: read error: %s\n", gpg_errstr(rc) ); + log_error("do_kbxf_enum: read error: %s\n", gpg_errstr(rc) ); rc = GPGERR_INV_KEYRING; goto ready; } @@ -2079,300 +1316,5 @@ do_kbxf_copy( KBPOS *kbpos, int mode, KBNODE root ) } - -#ifdef HAVE_LIBGDBM -/**************************************************************** - ********** Functions which operates on GDM files *************** - ****************************************************************/ - -#if MAX_FINGERPRINT_LEN > 20 - #error A GDBM keyring assumes that fingerprints are less than 21 -#endif - -/**************** - * Insert the keyblock into the GDBM database - */ - -static int -do_gdbm_store( KBPOS *kbpos, KBNODE root, int update ) -{ - RESTBL *rentry; - PKT_public_key *pk; - KBNODE kbctx, node; - IOBUF fp = NULL; - byte fpr[20]; - byte contbuf[21]; - byte keybuf[21]; - size_t fprlen; - datum key, content; - int i, rc; - - if( !(rentry = check_pos( kbpos )) ) - return GPGERR_GENERAL; - - if( opt.dry_run ) - return 0; - - /* construct the fingerprint which is used as the primary key */ - node = find_kbnode( root, PKT_PUBLIC_KEY ); - if( !node ) - log_bug("a gdbm database can't store secret keys\n"); - pk = node->pkt->pkt.public_key; - - fingerprint_from_pk( pk, fpr, &fprlen ); - for(i=fprlen; i < DIM(fpr); i++ ) - fpr[i] = 0; - - /* build the keyblock */ - kbctx=NULL; - fp = iobuf_temp(); - iobuf_put( fp, 1 ); /* data is a keyblock */ - while( (node = walk_kbnode( root, &kbctx, 0 )) ) { - if( (rc = build_packet( fp, node->pkt )) ) { - log_error("build_packet(%d) failed: %s\n", - node->pkt->pkttype, gpg_errstr(rc) ); - rc = GPGERR_WRITE_FILE; - goto leave; - } - } - /* store data and key */ - *keybuf = 1; /* key is a padded fingerprint */ - memcpy(keybuf+1, fpr, 20 ); - key.dptr = keybuf; - key.dsize = 21; - content.dptr = iobuf_get_temp_buffer( fp ); - content.dsize = iobuf_get_temp_length( fp ); - rc = gdbm_store( rentry->dbf, key, content, - update? GDBM_REPLACE : GDBM_INSERT ); - if( rc == 1 && !update ) - rc = gdbm_store( rentry->dbf, key, content, GDBM_REPLACE ); - - if( rc ) { - log_error("%s: gdbm_store failed: %s\n", rentry->fname, - rc == 1 ? "already stored" - : gdbm_strerror(gdbm_errno) ); - rc = GPGERR_WRITE_FILE; - goto leave; - } - /* now store all keyids */ - *contbuf = 2; /* data is a list of fingerprints */ - memcpy(contbuf+1, fpr, 20 ); - content.dptr = contbuf; - content.dsize= 21; - kbctx=NULL; - while( (node = walk_kbnode( root, &kbctx, 0 )) ) { - if( node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - u32 aki[2]; - - keyid_from_pk( node->pkt->pkt.public_key, aki ); - *keybuf = 2; /* key is a 8 byte keyid */ - u32tobuf( keybuf+1 , aki[0] ); - u32tobuf( keybuf+5, aki[1] ); - key.dptr = keybuf; - key.dsize= 9; - /* fixme: must be more clever when a insert failed: - * build a list of fingerprints in this case */ - rc = gdbm_store( rentry->dbf, key, content, - update? GDBM_REPLACE : GDBM_INSERT ); - if( rc ) { - log_info("%s: gdbm_store keyid failed: %s\n", rentry->fname, - rc == 1 ? "already stored" - : gdbm_strerror(gdbm_errno) ); - rc = 0; - } - } - } - - leave: - iobuf_close(fp); /* don't need a cancel because it is a temp iobuf */ - return rc; -} - -/**************** - * search one keybox, return 0 if found, -1 if not found or an errorcode. - */ -static int -do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, const byte *fpr, int fprlen ) -{ - byte *keybuf = kbpos->keybuf; - datum key; - int i; - - *keybuf = 1; - for(i=0; i < fprlen; i++ ) - keybuf[i+1] = fpr[i]; - for(; i < 20; i++ ) - keybuf[i+1] = 0; - - /* fetch the data */ - key.dptr = keybuf; - key.dsize = 21; - if( !gdbm_exists( dbf, key ) ) - return -1; /* not found */ - return 0; -} - -/**************** - * locate by keyid. - * FIXME: we must have a way to enumerate thru the list opf fingerprints - */ -static int -do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid ) -{ - byte keybuf[9]; - datum key, content; - int rc; - - /* construct the fingerprint which is used as the primary key */ - *keybuf = 2; - u32tobuf( keybuf+1, keyid[0] ); - u32tobuf( keybuf+5, keyid[1] ); - - /* fetch the data */ - key.dptr = keybuf; - key.dsize = 9; - content = gdbm_fetch( dbf, key ); - if( !content.dptr ) - return -1; - - if( content.dsize < 2 ) { - log_error("gdbm_fetch did not return enough data\n" ); - free( content.dptr ); /* can't use gcry_free() here */ - return GPGERR_INV_KEYRING; - } - if( *content.dptr != 2 ) { - log_error("gdbm_fetch returned unexpected type %d\n", - *(byte*)content.dptr ); - free( content.dptr ); /* can't use gcry_free() here */ - return GPGERR_INV_KEYRING; - } - if( content.dsize < 21 ) { - log_error("gdbm_fetch did not return a complete fingerprint\n" ); - free( content.dptr ); /* can't use gcry_free() here */ - return GPGERR_INV_KEYRING; - } - if( content.dsize > 21 ) - log_info("gdbm_fetch: WARNING: more than one fingerprint\n" ); - - rc = do_gdbm_locate( dbf, kbpos, content.dptr+1, 20 ); - free( content.dptr ); /* can't use gcry_free() here */ - return rc; -} - - - -static int -do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root ) -{ - PACKET *pkt; - int rc; - RESTBL *rentry; - KBNODE root = NULL; - IOBUF a; - datum key, content; - - if( !(rentry=check_pos(kbpos)) ) - return GPGERR_GENERAL; - - key.dptr = kbpos->keybuf; - key.dsize = 21; - content = gdbm_fetch( rentry->dbf, key ); - if( !content.dptr ) { - log_error("gdbm_fetch failed: %s\n", gdbm_strerror(gdbm_errno) ); - return GPGERR_INV_KEYRING; - } - if( content.dsize < 2 ) { - log_error("gdbm_fetch did not return enough data\n" ); - free( content.dptr ); /* can't use gcry_free() here */ - return GPGERR_INV_KEYRING; - } - if( *content.dptr != 1 ) { - log_error("gdbm_fetch returned unexpected type %d\n", - *(byte*)content.dptr ); - free( content.dptr ); /* can't use gcry_free() here */ - return GPGERR_INV_KEYRING; - } - - a = iobuf_temp_with_content( content.dptr+1, content.dsize-1 ); - free( content.dptr ); /* can't use gcry_free() here */ - - pkt = gcry_xmalloc( sizeof *pkt ); - init_packet(pkt); - kbpos->count=0; - while( (rc=parse_packet(a, pkt)) != -1 ) { - if( rc ) { /* ignore errors */ - if( rc != GPGERR_UNKNOWN_PACKET ) { - log_error("read_keyblock: read error: %s\n", gpg_errstr(rc) ); - rc = GPGERR_INV_KEYRING; - break; - } - kbpos->count++; - free_packet( pkt ); - init_packet( pkt ); - continue; - } - /* make a linked list of all packets */ - kbpos->count++; - if( !root ) - root = new_kbnode( pkt ); - else - add_kbnode( root, new_kbnode( pkt ) ); - pkt = gcry_xmalloc( sizeof *pkt ); - init_packet(pkt); - } - if( rc == -1 && root ) - rc = 0; - if( rc ) - release_kbnode( root ); - else - *ret_root = root; - free_packet( pkt ); - gcry_free( pkt ); - iobuf_close(a); - return rc; -} - - -/**************** - * Enum over keyblok data - */ -static int -do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root ) -{ - RESTBL *rentry; - datum key, helpkey; - - if( !(rentry=check_pos(kbpos)) ) - return GPGERR_GENERAL; - - if( !kbpos->offset ) { - kbpos->offset = 1; - key = gdbm_firstkey( rentry->dbf ); - } - else { - helpkey.dptr = kbpos->keybuf; - helpkey.dsize= 21; - key = gdbm_nextkey( rentry->dbf, helpkey ); - } - while( key.dptr && (!key.dsize || *key.dptr != 1) ) { - helpkey = key; - key = gdbm_nextkey( rentry->dbf, helpkey ); - free( helpkey.dptr ); /* free and not gcry_free() ! */ - } - if( !key.dptr ) - return -1; /* eof */ - - if( key.dsize < 21 ) { - free( key.dptr ); /* free and not gcry_free() ! */ - log_error("do_gdm_enum: key is too short\n" ); - return GPGERR_INV_KEYRING; - } - memcpy( kbpos->keybuf, key.dptr, 21 ); - free( key.dptr ); /* free and not gcry_free() ! */ - return do_gdbm_read( kbpos, ret_root ); -} - -#endif /*HAVE_LIBGDBM*/ diff --git a/g10/skclist.c b/g10/skclist.c index dceba71f8..bc325cd58 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -60,7 +60,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock, sk = gcry_xcalloc( 1, sizeof *sk ); sk->req_usage = use; - if( (rc = get_seckey_byname( sk, NULL, unlock )) ) { + if( (rc = get_seckey_byname( NULL, sk, NULL, unlock, NULL )) ) { free_secret_key( sk ); sk = NULL; log_error("no default secret key: %s\n", gpg_errstr(rc) ); } @@ -93,7 +93,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock, sk = gcry_xcalloc( 1, sizeof *sk ); sk->req_usage = use; - if( (rc = get_seckey_byname( sk, locusr->d, unlock )) ) { + if( (rc = get_seckey_byname( NULL, sk, locusr->d, unlock, NULL))) { free_secret_key( sk ); sk = NULL; log_error(_("skipped `%s': %s\n"), locusr->d, gpg_errstr(rc) ); }