aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2001-09-06 17:10:00 +0000
committerWerner Koch <[email protected]>2001-09-06 17:10:00 +0000
commited17c7afd07814c8a3315660045420257b57eb1a (patch)
treefa6ad801163248b1e40a2243449ab73fbd202005
parentbug fixes (diff)
downloadgnupg-ed17c7afd07814c8a3315660045420257b57eb1a.tar.gz
gnupg-ed17c7afd07814c8a3315660045420257b57eb1a.zip
Revamped the keyring code
-rw-r--r--ChangeLog4
-rw-r--r--INSTALL5
-rw-r--r--NEWS4
-rw-r--r--TODO4
-rw-r--r--checks/ChangeLog4
-rwxr-xr-xchecks/genkey1024.test114
-rw-r--r--configure.ac39
-rw-r--r--doc/ChangeLog4
-rw-r--r--doc/DETAILS4
-rw-r--r--doc/gpg.sgml2
-rw-r--r--doc/gpgv.sgml2
-rw-r--r--g10/ChangeLog54
-rw-r--r--g10/Makefile.am5
-rw-r--r--g10/delkey.c43
-rw-r--r--g10/export.c43
-rw-r--r--g10/g10.c13
-rw-r--r--g10/getkey.c705
-rw-r--r--g10/global.h29
-rw-r--r--g10/gpgv.c4
-rw-r--r--g10/import.c124
-rw-r--r--g10/keydb.c623
-rw-r--r--g10/keydb.h85
-rw-r--r--g10/keyedit.c74
-rw-r--r--g10/keygen.c128
-rw-r--r--g10/keyid.c8
-rw-r--r--g10/keylist.c43
-rw-r--r--g10/keyring.c1061
-rw-r--r--g10/keyring.h44
-rw-r--r--g10/keyring.obin0 -> 56784 bytes
-rw-r--r--g10/mainproc.c2
-rw-r--r--g10/options.h1
-rw-r--r--g10/packet.h8
-rw-r--r--g10/parse-packet.c19
-rw-r--r--g10/passphrase.c4
-rw-r--r--g10/pkclist.c44
-rw-r--r--g10/revoke.c38
-rw-r--r--g10/ringedit.c1796
-rw-r--r--g10/status.c1
-rw-r--r--g10/status.h2
-rw-r--r--g10/tdbdump.c2
-rw-r--r--g10/trustdb.c26
-rwxr-xr-xscripts/autogen.sh2
-rw-r--r--tools/gpgsplit.c1
-rw-r--r--util/ChangeLog4
-rw-r--r--util/miscutil.c4
45 files changed, 2463 insertions, 2763 deletions
diff --git a/ChangeLog b/ChangeLog
index ce427a664..e2ae693fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2001-09-03 Werner Koch <[email protected]>
+
+ * configure.ac: Removed GDBM tests.
+
2001-08-23 Werner Koch <[email protected]>
* configure.in (AC_FUNC_FSEEKO): Add.
diff --git a/INSTALL b/INSTALL
index 02510633d..4e443b27a 100644
--- a/INSTALL
+++ b/INSTALL
@@ -102,6 +102,11 @@ Specific problems on some machines
not build. In this case try to run configure using:
CFLAGS="-g -O2 -mcpu=powerpc" ./configure
+ * Compaq C V6.2 for alpha:
+
+ You may want to use the option "-msg-disable ptrmismatch1"
+ to get rid of the sign/unsigned char mismatch warnings.
+
The Random Device
diff --git a/NEWS b/NEWS
index 14fc3e6e2..1de9000b6 100644
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,10 @@
UID, encoded using %XX escaping (but with spaces left as spaces,
so that it should not break too much)
+ * Support for GDBM based keyrings has been removed.
+
+ * The entire keyring management has been revamped.
+
Noteworthy changes in version 1.0.6 (2001-05-29)
------------------------------------------------
diff --git a/TODO b/TODO
index fb0e332e6..ed9f2fe2f 100644
--- a/TODO
+++ b/TODO
@@ -73,11 +73,11 @@
* Concatenated encryption messages don't work corectly - only the
first one is processed.
- * Add status message for reasons why a key was not selected.
-
* Add option to put the list of recipients (from the encryption
layer) into the signatures notation data.
+ * Allow to update key signatyres, add status that a key is already signed.
+
Scheduled for 1.1
-----------------
* export by user-IDs does only export the first matching name which leads
diff --git a/checks/ChangeLog b/checks/ChangeLog
index b403d324d..48d76fb98 100644
--- a/checks/ChangeLog
+++ b/checks/ChangeLog
@@ -1,3 +1,7 @@
+2001-09-06 Werner Koch <[email protected]>
+
+ * genkey1024.test: Simplified by using a parameter file.
+
2001-05-30 Werner Koch <[email protected]>
* multisig.test (IFS): Reset IFS just before the test.
diff --git a/checks/genkey1024.test b/checks/genkey1024.test
index 4eb8370ae..e9852d7b6 100755
--- a/checks/genkey1024.test
+++ b/checks/genkey1024.test
@@ -2,99 +2,25 @@
. $srcdir/defs.inc || exit 3
-
-if (expect -v) < /dev/null > /dev/null 2>&1 ; then
- :
-else
- echo "\"expect\" needed but not found - test skipped"
- exit 0
-fi
-
-LANG=
-LANGUAGE=
-
-expect - <<EOF >/dev/null
-#set timeout -1
-set timeout 8
-match_max 100000
-spawn ../g10/gpg --no-batch --quick-random --homedir . --gen-key
-expect {
- -exact "Please select what kind of key you want:\r
- (1) DSA and ElGamal (default)\r
- (2) DSA (sign only)\r
- (4) ElGamal (sign and encrypt)\r
-Your selection? " { send -- "1\r" }
- timeout { exit 1 } }
-expect {
- -exact "1\r
-\r \rDSA keypair will have 1024 bits.\r
-About to generate a new ELG-E keypair.\r
- minimum keysize is 768 bits\r
- default keysize is 1024 bits\r
- highest suggested keysize is 2048 bits\r
-What keysize do you want? (1024) " { send -- "\r" }
- timeout { exit 1 } }
-expect {
- -exact "\r
-\r \rRequested keysize is 1024 bits\r
-Please specify how long the key should be valid.\r
- 0 = key does not expire\r
- <n> = key expires in n days\r
- <n>w = key expires in n weeks\r
- <n>m = key expires in n months\r
- <n>y = key expires in n years\r
-Key is valid for? (0) " { send -- "1\r" }
- timeout { exit 1 } }
-expect {
- -exact "1\r
-\r \rKey expires at " { }
- timeout { exit 1 } }
-expect {
- -re "(.*)\r
-" {}
- timeout { exit 1 } }
-expect {
- -exact "Is this correct (y/n)? " { send -- "y\r" }
- timeout { exit 1 } }
-expect {
- -exact "y\r
-\r \r\r
-You need a User-ID to identify your key; the software constructs the user id\r
-from Real Name, Comment and Email Address in this form:\r
- \"Heinrich Heine (Der Dichter) <[email protected]>\"\r
-\r
-Real name: " { send -- "Harry H.\r" }
- timeout { exit 1 } }
-expect {
- -exact "Harry H.\r
-\r \rEmail address: " { send -- "[email protected]\r" }
- timeout { exit 1 } }
-expect {
- -exact "[email protected]\r
-\r \rComment: " { send -- "a test\r" }
- timeout { exit 1 } }
-expect {
- -exact "a test\r
-\r \rYou selected this USER-ID:\r
- \"Harry H. (a test) <[email protected]> (INSECURE!)\"\r
-\r
-Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? " { send -- "o\r" }
- timeout { exit 1 } }
-expect {
- -exact "o\r
-\r \rYou need a Passphrase to protect your secret key.\r
-\r
-Enter passphrase: " { sleep 1; send -- "abc\r" }
- timeout { exit 1 } }
-expect {
- -ex "\r \rRepeat passphrase: " { sleep 1; send -- "abc\r" }
- timeout { exit 1 } }
-set timeout 600
-expect {
- -re "^.*\r\npublic and secret key" { exit 0 }
- eof { exit 1 }
-}
-exit 1
+../g10/gpg --quiet --batch --quick-random --homedir . --gen-key <<EOF
+Key-Type: DSA
+Key-Length: 1024
+Subkey-Type: ELG-E
+Subkey-Length: 1024
+Name-Real: Harry H.
+Name-Comment: test key
+Name-Email: hh@@ddorf.de
+Expire-Date: 1
+Passphrase: abc
+%commit
+Key-Type: RSA
+Key-Length: 1024
+Key-Usage: sign,encrypt
+Name-Real: Harry A.
+Name-Comment: RSA test key
+Name-Email: hh@@ddorf.de
+Expire-Date: 2
+Passphrase: abc
+%commit
EOF
-#*-*wedit:notab*-*
diff --git a/configure.ac b/configure.ac
index c80734a1a..608bdbdbe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -183,7 +183,6 @@ MPI_OPT_FLAGS=""
try_gettext=yes
-try_gdbm=yes
case "${target}" in
*-*-mingw32*)
# special stuff for Windoze NT
@@ -201,7 +200,6 @@ case "${target}" in
MingW32 systems and these systems lack Posix functions,
we use a simplified version of gettext])
try_gettext="no"
- try_gdbm="no"
;;
i?86-emx-os2 | i?86-*-os2*emx )
# OS/2 with the EMX environment
@@ -209,7 +207,6 @@ case "${target}" in
AC_DEFINE(HAVE_DRIVE_LETTERS)
AC_DEFINE(HAVE_DOSISH_SYSTEM)
try_gettext="no"
- try_gdbm="no"
;;
i?86-*-msdosdjgpp*)
@@ -218,7 +215,6 @@ case "${target}" in
AC_DEFINE(HAVE_DRIVE_LETTERS)
AC_DEFINE(HAVE_DOSISH_SYSTEM)
try_gettext="no"
- try_gdbm="no"
;;
*-*-freebsd*)
@@ -363,41 +359,6 @@ AC_SUBST(USE_INCLUDED_LIBINTL)
AC_SUBST(BUILD_INCLUDED_LIBINTL)
fi
-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 This old test is here just for reference tin case it fails:
-dnl
-dnl Solaris needs -lsocket and -lnsl. Unisys system includes
-dnl gethostbyname in libsocket but needs libnsl for socket.
-dnl The test does not workfor all system, so some are hardcoded here.
-dnl case "${target}" in
-dnl i386-univel-sysv4*)
-dnl LIBS="$LIBS -lsocket -lnsl"
-dnl ;;
-dnl *)
-dnl AC_CHECK_LIB(nsl, gethostbyname)
-dnl AC_CHECK_LIB(socket, socket, ac_need_libsocket=1, ac_try_nsl=1)
-dnl if test x$ac_need_libsocket = x1; then
-dnl LIBS="$LIBS -lsocket"
-dnl fi
-dnl if test x$ac_try_nsl = x1; then
-dnl AC_CHECK_LIB(nsl, gethostbyname, ac_need_libnsl=1)
-dnl if test x$ac_need_libnsl = x1
-dnl then
-dnl LIBS="$LIBS -lnsl"
-dnl fi
-dnl fi
-dnl ;;
-dnl esac
AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, gethostbyname))
AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 64d043802..d9ef0eaf8 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,7 @@
+2001-09-03 Werner Koch <[email protected]>
+
+ * gpg.sgml, gpgv.sgml: Removed GDBM stuff.
+
2001-08-29 Werner Koch <[email protected]>
* faq.raw: Described how to delete a secret key w/o a public key
diff --git a/doc/DETAILS b/doc/DETAILS
index cc326d80b..807f374d7 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -283,6 +283,10 @@ more arguments in future versions.
END_STREAM
Issued by pipemode.
+ INV_RECP <reason> <requested_recipient>
+ Issued for each unusable recipient. The only reason code
+ currently defined is 0 for "No specific reason given".
+
Key generation
==============
diff --git a/doc/gpg.sgml b/doc/gpg.sgml
index 1a1d71aa7..f27249971 100644
--- a/doc/gpg.sgml
+++ b/doc/gpg.sgml
@@ -839,8 +839,6 @@ does not contain a slash, it is assumed to be in the
home-directory ("~/.gnupg" if --homedir is not used).
The filename may be prefixed with a scheme:</para>
<para>"gnupg-ring:" is the default one.</para>
-<para>"gnupg-gdbm:" may be used for a GDBM ring. Note that GDBM
-is experimental and likely to be removed in future versions.</para>
<para>It might make sense to use it together with --no-default-keyring.
</para></listitem></varlistentry>
diff --git a/doc/gpgv.sgml b/doc/gpgv.sgml
index 757c8fe7c..4119b41dc 100644
--- a/doc/gpgv.sgml
+++ b/doc/gpgv.sgml
@@ -119,8 +119,6 @@ does not contain a slash, it is assumed to be in the
home-directory ("~/.gnupg" if --homedir is not used).
The filename may be prefixed with a scheme:</para>
<para>"gnupg-ring:" is the default one.</para>
-<para>"gnupg-gdbm:" may be used for a GDBM ring. Note that GDBM
-is experimental and likely to be removed in future versions.</para>
<para>It might make sense to use it together with --no-default-keyring.
</para></listitem></varlistentry>
diff --git a/g10/ChangeLog b/g10/ChangeLog
index aca8f7bb3..6a2025723 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,57 @@
+2001-09-06 Werner Koch <[email protected]>
+
+ * getkey.c (fixup_uidnode): Features flag is now a bit vector.
+ * keygen.c (add_feature_mdc): Ditto.
+
+ Revamped the entire key I/O code to be prepared for other ways of
+ key storages and to get rid of the existing shit. GDBM support has
+ gone.
+ * keydb.c: New
+ * keyring.c, keyring.h: New.
+ * ringedit.c: Removed. Moved some stuff to keyring.c
+ * getkey.c: Changed everything related to the key retrieving
+ functions which are now using the keydb_ functions.
+ (prepare_search, word_match_chars, word_match)
+ (prepare_word_match, compare_name): Moved to keyring.c
+ (get_pubkey_byname): Removed ctx arg and add ret_kdbhd
+ arg. Changed all callers.
+ (key_byname): Use get_pubkey_end to release the context and take
+ new ret_kbdhd arg. Changed all callers.
+ (classify_user_id2): Fill the 16 byte fingerprint up with 4 null
+ bytes not with zero bytes of value 4, tsss.
+ * import.c (import_one): Updated to use the new keydb interface.
+ (import_secret_one): Ditto.
+ (import_revoke_cert): Ditto.
+ * delkey.c (do_delete_key): Ditto.
+ * keyedit.c (keyedit_menu): Ditto.
+ (get_keyblock_byname): Removed.
+ * revoke.c (gen_revoke): Ditto.
+ * export.c (do_export_stream): Ditto.
+ * trustdb.c (update_trustdb): Ditto.
+ * g10.c, gpgv.c (main): Renamed add_keyblock_resource to
+ keydb_add_resource.
+ * Makefile.am: Added and removed files.
+
+ * keydb.h: Moved KBNODE typedef and MAX_FINGERPRINT_LEN to
+ * global.h: this new header.
+
+2001-09-03 Werner Koch <[email protected]>
+
+ * passphrase.c (agent_get_passphrase): Changed nread to size_t.
+ (passphrase_clear_cache): Ditto.
+
+ * keyid.c (mk_datestr): Avoid trigraphs.
+ (fingerprint_from_pk): Cache the keyid in the pk.
+
+ * options.h: Add opt.with_fingerprint so that we know whether the
+ corresponding options was used.
+ * g10.c (main): Set it here.
+ * pkclist.c (check_signatures_trust): Always print fingerprint
+ when this option is used. Mixed a minor memory leak.
+
+ * status.c, status.h: New status INV_RECP.
+ * pkclist.c (build_pk_list): Issue this status.
+
2001-08-31 Werner Koch <[email protected]>
* parse-packet.c (parse_key,parse_pubkeyenc)
diff --git a/g10/Makefile.am b/g10/Makefile.am
index f77d8d32a..b7ead7e76 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -28,14 +28,15 @@ needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
bin_PROGRAMS = gpg gpgv
common_source = \
+ global.h \
build-packet.c \
compress.c \
filter.h \
free-packet.c \
getkey.c \
- ringedit.c \
+ keydb.c keydb.h \
+ keyring.c keyring.h \
seskey.c \
- keydb.h \
kbnode.c \
main.h \
mainproc.c \
diff --git a/g10/delkey.c b/g10/delkey.c
index 777d4c174..57ba41b67 100644
--- a/g10/delkey.c
+++ b/g10/delkey.c
@@ -52,37 +52,35 @@ do_delete_key( const char *username, int secret, int *r_sec_avail )
int rc = 0;
KBNODE keyblock = NULL;
KBNODE node;
- KBPOS kbpos;
+ KEYDB_HANDLE hd = keydb_new (secret);
PKT_public_key *pk = NULL;
PKT_secret_key *sk = NULL;
u32 keyid[2];
int okay=0;
int yes;
+ KEYDB_SEARCH_DESC desc;
*r_sec_avail = 0;
- /* search the userid */
- if (secret
- && classify_user_id (username, keyid, NULL, NULL, NULL) == 11) {
- /* if the user supplied a long keyID we use the direct search
- methods which allows us to delete a key if the
- corresponding secret key is missing */
- rc = find_secret_keyblock_direct (&kbpos, keyid);
- }
- else if (secret)
- rc = find_secret_keyblock_byname (&kbpos, username);
- else
- rc = find_keyblock_byname (&kbpos, username);
- if( rc ) {
- log_error(_("%s: user not found\n"), username );
+ /* search the userid */
+ memset (&desc, 0, sizeof desc);
+ desc.mode = classify_user_id (username,
+ desc.u.kid,
+ desc.u.fpr,
+ &desc.u.name,
+ NULL);
+
+ rc = desc.mode? keydb_search (hd, &desc, 1):G10ERR_INV_USER_ID;
+ if (rc) {
+ log_error (_("key `%s' not found: %s\n"), username, g10_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, g10_errstr(rc) );
+ rc = keydb_get_keyblock (hd, &keyblock );
+ if (rc) {
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
goto leave;
}
@@ -159,15 +157,16 @@ do_delete_key( const char *username, int secret, int *r_sec_avail )
if( okay ) {
- rc = delete_keyblock( &kbpos );
- if( rc ) {
- log_error("delete_keyblock failed: %s\n", g10_errstr(rc) );
+ rc = keydb_delete_keyblock (hd);
+ if (rc) {
+ log_error (_("deleting keyblock failed: %s\n"), g10_errstr(rc) );
goto leave;
}
}
leave:
- release_kbnode( keyblock );
+ keydb_release (hd);
+ release_kbnode (keyblock);
return rc;
}
diff --git a/g10/export.c b/g10/export.c
index 05efef0d0..138701158 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -112,58 +112,56 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
PACKET pkt;
KBNODE keyblock = NULL;
KBNODE kbctx, node;
- KBPOS kbpos;
+ KEYDB_HANDLE kdbhd;
STRLIST sl;
int all = !users;
+ int all_first = 1;
*any = 0;
memset( &zfx, 0, sizeof zfx);
init_packet( &pkt );
+ kdbhd = keydb_new (secret);
+
if( opt.compress_keys && opt.compress )
iobuf_push_filter( out, compress_filter, &zfx );
- if( all ) {
- rc = enum_keyblocks( secret?5:0, &kbpos, &keyblock );
- if( rc ) {
- if( rc != -1 )
- log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) );
- goto leave;
- }
- all = 2;
- }
-
/* use the correct sequence. strlist_last,prev do work correctly with
* NULL pointers :-) */
for( sl=strlist_last(users); sl || all ; sl=strlist_prev( users, sl )) {
if( all ) { /* get the next user */
- rc = enum_keyblocks( 1, &kbpos, &keyblock );
+ rc = all_first ? keydb_search_first (kdbhd)
+ : keydb_search_next (kdbhd);
+ all_first = 0;
if( rc == -1 ) /* EOF */
break;
if( rc ) {
- log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc));
+ log_error ("error searching key: %s\n", g10_errstr(rc));
break;
}
}
else {
- /* search the userid */
- rc = secret? find_secret_keyblock_byname( &kbpos, sl->d )
- : find_keyblock_byname( &kbpos, sl->d );
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = classify_user_id (sl->d, desc.u.kid, desc.u.fpr,
+ &desc.u.name, NULL);
+ rc = desc.mode? keydb_search (kdbhd, &desc, 1):G10ERR_INV_USER_ID;
if( rc ) {
- log_error(_("%s: user not found: %s\n"), sl->d, g10_errstr(rc));
+ log_error (_("key `%s' not found: %s\n"),
+ sl->d, g10_errstr (rc));
rc = 0;
continue;
}
- /* read the keyblock */
- rc = read_keyblock( &kbpos, &keyblock );
}
+ /* read the keyblock */
+ rc = keydb_get_keyblock (kdbhd, &keyblock );
if( rc ) {
- log_error(_("certificate read problem: %s\n"), g10_errstr(rc));
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
goto leave;
}
-
/* do not export keys which are incompatible with rfc2440 */
if( onlyrfc && (node = find_kbnode( keyblock, PKT_PUBLIC_KEY )) ) {
PKT_public_key *pk = node->pkt->pkt.public_key;
@@ -229,8 +227,7 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
rc = 0;
leave:
- if( all == 2 )
- enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+ keydb_release (kdbhd);
release_kbnode( keyblock );
if( !*any )
log_info(_("WARNING: nothing exported\n"));
diff --git a/g10/g10.c b/g10/g10.c
index 7892b3e25..1646853a8 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -886,7 +886,8 @@ main( int argc, char **argv )
break;
#endif /* __riscos__ */
case oWithFingerprint:
- with_fpr=1; /*fall thru*/
+ opt.with_fingerprint = 1;
+ with_fpr=1; /*fall thru*/
case oFingerprint: opt.fingerprint++; break;
case oSecretKeyring: append_to_strlist( &sec_nrings, pargs.r.ret_str); break;
case oOptions:
@@ -1225,13 +1226,13 @@ main( int argc, char **argv )
&& !(cmd == aKMode && argc == 2 ) ) {
if( !sec_nrings || default_keyring ) /* add default secret rings */
- add_keyblock_resource("secring" EXTSEP_S "gpg", 0, 1);
+ keydb_add_resource ("secring" EXTSEP_S "gpg", 0, 1);
for(sl = sec_nrings; sl; sl = sl->next )
- add_keyblock_resource( sl->d, 0, 1 );
+ keydb_add_resource ( sl->d, 0, 1 );
if( !nrings || default_keyring ) /* add default ring */
- add_keyblock_resource("pubring" EXTSEP_S "gpg", 0, 0);
+ keydb_add_resource ("pubring" EXTSEP_S "gpg", 0, 0);
for(sl = nrings; sl; sl = sl->next )
- add_keyblock_resource( sl->d, 0, 0 );
+ keydb_add_resource ( sl->d, 0, 0 );
}
FREE_STRLIST(nrings);
FREE_STRLIST(sec_nrings);
@@ -1445,7 +1446,7 @@ main( int argc, char **argv )
else {
/* add keyring (default keyrings are not registered in this
* special case */
- add_keyblock_resource( argv[1], 0, 0 );
+ keydb_add_resource( argv[1], 0, 0 );
sl = NULL;
if (**argv)
add_to_strlist2( &sl, *argv, utf8_strings );
diff --git a/g10/getkey.c b/g10/getkey.c
index 8293fc673..5b013efa4 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -34,7 +34,6 @@
#include "trustdb.h"
#include "i18n.h"
-
#define MAX_UNK_CACHE_ENTRIES 1000 /* we use a linked list - so I guess
* this is a reasonable limit */
#define MAX_PK_CACHE_ENTRIES 200
@@ -45,60 +44,6 @@
#endif
-/* A map of the all characters valid used for word_match()
- * Valid characters are in in this table converted to uppercase.
- * 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
- * EBCDIC character set (user ids are UTF-8).
- * wk 2000-04-13: Hmmm, does this really make sense, given the fact that
- * we can run gpg now on a S/390 running GNU/Linux, where the code
- * translation is done by the device drivers?
- */
-static const byte word_match_chars[256] = {
- /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- /* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 40 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- /* 48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- /* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- /* 58 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 60 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- /* 68 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- /* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- /* 78 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- /* 88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- /* 90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- /* 98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- /* a0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- /* a8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- /* b0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- /* b8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- /* c0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- /* c8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- /* d0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- /* d8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- /* e0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- /* e8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- /* f0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- /* f8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
-};
-
-typedef struct {
- int mode;
- u32 keyid[2];
- byte fprint[20];
- char *namebuf;
- const char *name;
-} getkey_item_t;
-
struct getkey_ctx_s {
int exact;
KBNODE keyblock;
@@ -107,10 +52,10 @@ struct getkey_ctx_s {
int last_rc;
int req_usage;
int req_algo;
- ulong count;
+ KEYDB_HANDLE kr_handle;
int not_allocated;
int nitems;
- getkey_item_t items[1];
+ KEYDB_SEARCH_DESC items[1];
};
#if 0
@@ -157,11 +102,8 @@ typedef struct user_id_db {
static user_id_db_t user_id_db;
static int uid_cache_entries; /* number of entries in uid cache */
-
-
-static char* prepare_word_match( const byte *name );
-static int lookup( GETKEY_CTX ctx, KBNODE *ret_kb, int secmode );
static void merge_selfsigs( KBNODE keyblock );
+static int lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode );
#if 0
@@ -426,10 +368,11 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
memset( &ctx, 0, sizeof ctx );
ctx.exact = 1; /* use the key ID exactly as given */
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
+ ctx.items[0].u.kid[0] = keyid[0];
+ ctx.items[0].u.kid[1] = keyid[1];
ctx.req_algo = pk->req_algo;
ctx.req_usage = pk->req_usage;
rc = lookup( &ctx, &kb, 0 );
@@ -480,12 +423,13 @@ get_pubkeyblock( u32 *keyid )
KBNODE keyblock = NULL;
memset( &ctx, 0, sizeof ctx );
- /* co need to set exact here because we want the entire block */
+ /* no need to set exact here because we want the entire block */
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
+ ctx.items[0].u.kid[0] = keyid[0];
+ ctx.items[0].u.kid[1] = keyid[1];
rc = lookup( &ctx, &keyblock, 0 );
get_pubkey_end( &ctx );
@@ -508,10 +452,11 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
memset( &ctx, 0, sizeof ctx );
ctx.exact = 1; /* use the key ID exactly as given */
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (1);
ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
+ ctx.items[0].u.kid[0] = keyid[0];
+ ctx.items[0].u.kid[1] = keyid[1];
ctx.req_algo = sk->req_algo;
ctx.req_usage = sk->req_usage;
rc = lookup( &ctx, &kb, 1 );
@@ -542,8 +487,13 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
int
seckey_available( u32 *keyid )
{
- KBPOS dummy_kbpos;
- return find_secret_keyblock_direct (&dummy_kbpos, keyid)? G10ERR_NO_SECKEY:0;
+ int rc;
+ KEYDB_HANDLE hd = keydb_new (1);
+ rc = keydb_search_kid (hd, keyid);
+ if ( rc == -1 )
+ rc = G10ERR_NO_SECKEY;
+ keydb_release (hd);
+ return rc;
}
@@ -638,36 +588,36 @@ classify_user_id2( const char *name, u32 *keyid, byte *fprint,
return 0;
case '.': /* an email address, compare from end */
- mode = 5;
+ mode = KEYDB_SEARCH_MODE_MAILEND;
s++;
break;
case '<': /* an email address */
- mode = 3;
+ mode = KEYDB_SEARCH_MODE_MAIL;
break;
case '@': /* part of an email address */
- mode = 4;
+ mode = KEYDB_SEARCH_MODE_MAILSUB;
s++;
break;
case '=': /* exact compare */
- mode = 1;
+ mode = KEYDB_SEARCH_MODE_EXACT;
s++;
break;
case '*': /* case insensitive substring search */
- mode = 2;
+ mode = KEYDB_SEARCH_MODE_SUBSTR;
s++;
break;
case '+': /* compare individual words */
- mode = 6;
+ mode = KEYDB_SEARCH_MODE_WORDS;
s++;
break;
case '#': /* local user id */
- mode = 12;
+ mode = KEYDB_SEARCH_MODE_TDBIDX;
s++;
if (keyid) {
if (keyid_from_lid(strtoul(s, NULL, 10), keyid))
@@ -696,7 +646,7 @@ classify_user_id2( const char *name, u32 *keyid, byte *fprint,
fprint[i]= 0;
}
s = se + 1;
- mode = 21;
+ mode = KEYDB_SEARCH_MODE_FPR;
}
break;
@@ -732,7 +682,7 @@ classify_user_id2( const char *name, u32 *keyid, byte *fprint,
keyid[0] = 0;
keyid[1] = strtoul( s, NULL, 16 );
}
- mode = 10;
+ mode = KEYDB_SEARCH_MODE_SHORT_KID;
}
else if (hexlength == 16
|| (!hexprefix && hexlength == 17 && *s == '0')) {
@@ -743,7 +693,7 @@ classify_user_id2( const char *name, u32 *keyid, byte *fprint,
mem2str(buf, s, 9 );
keyid[0] = strtoul( buf, NULL, 16 );
keyid[1] = strtoul( s+8, NULL, 16 );
- mode = 11;
+ mode = KEYDB_SEARCH_MODE_LONG_KID;
}
else if (hexlength == 32 || (!hexprefix && hexlength == 33
&& *s == '0')) {
@@ -752,7 +702,7 @@ classify_user_id2( const char *name, u32 *keyid, byte *fprint,
if (hexlength == 33)
s++;
if (fprint) {
- memset(fprint+16, 4, 0);
+ memset(fprint+16, 0, 4);
for (i=0; i < 16; i++, s+=2) {
int c = hextobyte(s);
if (c == -1)
@@ -760,7 +710,7 @@ classify_user_id2( const char *name, u32 *keyid, byte *fprint,
fprint[i] = c;
}
}
- mode = 16;
+ mode = KEYDB_SEARCH_MODE_FPR16;
}
else if (hexlength == 40 || (!hexprefix && hexlength == 41
&& *s == '0')) {
@@ -776,14 +726,14 @@ classify_user_id2( const char *name, u32 *keyid, byte *fprint,
fprint[i] = c;
}
}
- mode = 20;
+ mode = KEYDB_SEARCH_MODE_FPR20;
}
else {
if (hexprefix) /* This was a hex number with a prefix */
return 0; /* and a wrong length */
*force_exact = 0;
- mode = 2; /* Default is case insensitive substring search */
+ mode = KEYDB_SEARCH_MODE_SUBSTR; /* default mode */
}
}
@@ -815,7 +765,7 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
static int
key_byname( GETKEY_CTX *retctx, STRLIST namelist,
PKT_public_key *pk, PKT_secret_key *sk, int secmode,
- KBNODE *ret_kb )
+ KBNODE *ret_kb, KEYDB_HANDLE *ret_kdbhd )
{
int rc = 0;
int n;
@@ -824,24 +774,27 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
KBNODE help_kb = NULL;
int exact;
- if( retctx ) /* reset the returned context in case of error */
+ if( retctx ) {/* reset the returned context in case of error */
+ assert (!ret_kdbhd); /* not allowed because the handle is
+ stored in the context */
*retctx = NULL;
+ }
+ if (ret_kdbhd)
+ *ret_kdbhd = NULL;
/* build the search context */
- /* Performance hint: Use a static buffer if there is only one name */
- /* and we don't have mode 6 */
for(n=0, r=namelist; r; r = r->next )
n++;
- ctx = m_alloc_clear( sizeof *ctx + (n-1)*sizeof ctx->items );
+ ctx = m_alloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items );
ctx->nitems = n;
for(n=0, r=namelist; r; r = r->next, n++ ) {
int mode = classify_user_id2 ( r->d,
- ctx->items[n].keyid,
- ctx->items[n].fprint,
- &ctx->items[n].name,
+ ctx->items[n].u.kid,
+ ctx->items[n].u.fpr,
+ &ctx->items[n].u.name,
NULL, &exact );
-
+
if ( exact )
ctx->exact = 1;
ctx->items[n].mode = mode;
@@ -849,14 +802,9 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
m_free( ctx );
return G10ERR_INV_USER_ID;
}
- if( ctx->items[n].mode == 6 ) {
- ctx->items[n].namebuf = prepare_word_match(ctx->items[n].name);
- ctx->items[n].name = ctx->items[n].namebuf;
- }
}
-
-
+ ctx->kr_handle = keydb_new (secmode);
if ( !ret_kb )
ret_kb = &help_kb;
@@ -883,29 +831,34 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
release_kbnode ( help_kb );
- if( retctx ) /* caller wants the context */
+ if (retctx) /* caller wants the context */
*retctx = ctx;
else {
- /* Hmmm, why not get_pubkey-end here?? */
- enum_keyblocks( 2, &ctx->kbpos, NULL );
- memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
- for(n=0; n < ctx->nitems; n++ )
- m_free( ctx->items[n].namebuf );
- m_free( ctx );
+ if (ret_kdbhd) {
+ *ret_kdbhd = ctx->kr_handle;
+ ctx->kr_handle = NULL;
+ }
+ get_pubkey_end (ctx);
}
return rc;
}
+/*
+ * Find a public key from NAME and returh the keyblock or the key.
+ * If ret_kdb is not NULL, the KEYDB handle used to locate this keyblock is
+ * returned and the caller is responsible for closing it.
+ */
int
-get_pubkey_byname( GETKEY_CTX *retctx, PKT_public_key *pk,
- const char *name, KBNODE *ret_keyblock )
+get_pubkey_byname (PKT_public_key *pk,
+ const char *name, KBNODE *ret_keyblock,
+ KEYDB_HANDLE *ret_kdbhd )
{
int rc;
STRLIST namelist = NULL;
add_to_strlist( &namelist, name );
- rc = key_byname( retctx, namelist, pk, NULL, 0, ret_keyblock );
+ rc = key_byname( NULL, namelist, pk, NULL, 0, ret_keyblock, ret_kdbhd);
free_strlist( namelist );
return rc;
}
@@ -914,7 +867,7 @@ int
get_pubkey_bynames( GETKEY_CTX *retctx, PKT_public_key *pk,
STRLIST names, KBNODE *ret_keyblock )
{
- return key_byname( retctx, names, pk, NULL, 0, ret_keyblock );
+ return key_byname( retctx, names, pk, NULL, 0, ret_keyblock, NULL);
}
int
@@ -934,12 +887,8 @@ void
get_pubkey_end( GETKEY_CTX ctx )
{
if( ctx ) {
- int n;
-
- enum_keyblocks( 2, &ctx->kbpos, NULL );
memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
- for(n=0; n < ctx->nitems; n++ )
- m_free( ctx->items[n].namebuf );
+ keydb_release (ctx->kr_handle);
if( !ctx->not_allocated )
m_free( ctx );
}
@@ -967,9 +916,10 @@ get_pubkey_byfprint( PKT_public_key *pk,
memset( &ctx, 0, sizeof ctx );
ctx.exact = 1 ;
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
ctx.items[0].mode = fprint_len;
- memcpy( ctx.items[0].fprint, fprint, fprint_len );
+ memcpy( ctx.items[0].u.fpr, fprint, fprint_len );
rc = lookup( &ctx, &kb, 0 );
if (!rc && pk )
pk_from_block ( &ctx, pk, kb );
@@ -996,9 +946,11 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = fprint_len;
- memcpy( ctx.items[0].fprint, fprint, fprint_len );
+ ctx.items[0].mode = fprint_len==16? KEYDB_SEARCH_MODE_FPR16
+ : KEYDB_SEARCH_MODE_FPR20;
+ memcpy( ctx.items[0].u.fpr, fprint, fprint_len );
rc = lookup( &ctx, ret_keyblock, 0 );
get_pubkey_end( &ctx );
}
@@ -1025,10 +977,11 @@ get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
memset( &ctx, 0, sizeof ctx );
ctx.exact = 1;
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = 12;
- ctx.items[0].keyid[0] = kid[0];
- ctx.items[0].keyid[1] = kid[1];
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
+ ctx.items[0].u.kid[0] = kid[0];
+ ctx.items[0].u.kid[1] = kid[1];
rc = lookup( &ctx, ret_keyblock, 0 );
get_pubkey_end( &ctx );
@@ -1053,7 +1006,7 @@ get_seckey_byname2( GETKEY_CTX *retctx,
if( !name && opt.def_secret_key && *opt.def_secret_key ) {
add_to_strlist( &namelist, opt.def_secret_key );
- rc = key_byname( retctx, namelist, NULL, sk, 1, retblock );
+ rc = key_byname( retctx, namelist, NULL, sk, 1, retblock, NULL );
}
else if( !name ) { /* use the first one as default key */
struct getkey_ctx_s ctx;
@@ -1063,8 +1016,9 @@ get_seckey_byname2( GETKEY_CTX *retctx,
assert (!retblock);
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (1);
ctx.nitems = 1;
- ctx.items[0].mode = 15;
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_FIRST;
rc = lookup( &ctx, &kb, 1 );
if (!rc && sk )
sk_from_block ( &ctx, sk, kb );
@@ -1073,7 +1027,7 @@ get_seckey_byname2( GETKEY_CTX *retctx,
}
else {
add_to_strlist( &namelist, name );
- rc = key_byname( retctx, namelist, NULL, sk, 1, retblock );
+ rc = key_byname( retctx, namelist, NULL, sk, 1, retblock, NULL );
}
free_strlist( namelist );
@@ -1095,7 +1049,7 @@ int
get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk,
STRLIST names, KBNODE *ret_keyblock )
{
- return key_byname( retctx, names, NULL, sk, 1, ret_keyblock );
+ return key_byname( retctx, names, NULL, sk, 1, ret_keyblock, NULL );
}
@@ -1120,150 +1074,6 @@ get_seckey_end( GETKEY_CTX ctx )
-/*******************************************************
- ************** compare functions **********************
- *******************************************************/
-
-/****************
- * Do a word match (original user id starts with a '+').
- * The pattern is already tokenized to a more suitable format:
- * There are only the real words in it delimited by one space
- * and all converted to uppercase.
- *
- * Returns: 0 if all words match.
- *
- * Note: This algorithm is a straightforward one and not very
- * fast. It works for UTF-8 strings. The uidlen should
- * be removed but due to the fact that old versions of
- * pgp don't use UTF-8 we still use the length; this should
- * be fixed in parse-packet (and replace \0 by some special
- * UTF-8 encoding)
- */
-static int
-word_match( const byte *uid, size_t uidlen, const byte *pattern )
-{
- size_t wlen, n;
- const byte *p;
- const byte *s;
-
- for( s=pattern; *s; ) {
- do {
- /* skip leading delimiters */
- while( uidlen && !word_match_chars[*uid] )
- uid++, uidlen--;
- /* get length of the word */
- n = uidlen; p = uid;
- while( n && word_match_chars[*p] )
- p++, n--;
- wlen = p - uid;
- /* and compare against the current word from pattern */
- for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
- if( word_match_chars[*p] != s[n] )
- break;
- }
- if( n == wlen && (s[n] == ' ' || !s[n]) )
- break; /* found */
- uid += wlen;
- uidlen -= wlen;
- } while( uidlen );
- if( !uidlen )
- return -1; /* not found */
-
- /* advance to next word in pattern */
- for(; *s != ' ' && *s ; s++ )
- ;
- if( *s )
- s++ ;
- }
- return 0; /* found */
-}
-
-/****************
- * prepare word word_match; that is parse the name and
- * build the pattern.
- * caller has to free the returned pattern
- */
-static char*
-prepare_word_match( const byte *name )
-{
- byte *pattern, *p;
- int c;
-
- /* the original length is always enough for the pattern */
- p = pattern = m_alloc(strlen(name)+1);
- do {
- /* skip leading delimiters */
- while( *name && !word_match_chars[*name] )
- name++;
- /* copy as long as we don't have a delimiter and convert
- * to uppercase.
- * fixme: how can we handle utf8 uppercasing */
- for( ; *name && (c=word_match_chars[*name]); name++ )
- *p++ = c;
- *p++ = ' '; /* append pattern delimiter */
- } while( *name );
- p[-1] = 0; /* replace last pattern delimiter by EOS */
-
- return pattern;
-}
-
-
-
-
-
-static int
-compare_name( const char *uid, size_t uidlen, const char *name, int mode )
-{
- int i;
- const char *s, *se;
-
- if( mode == 1 ) { /* exact match */
- for(i=0; name[i] && uidlen; i++, uidlen-- )
- if( uid[i] != name[i] )
- break;
- if( !uidlen && !name[i] )
- return 0; /* found */
- }
- else if( mode == 2 ) { /* case insensitive substring */
- if( ascii_memistr( uid, uidlen, name ) )
- return 0;
- }
- else if( mode >= 3 && mode <= 5 ) { /* look at the email address */
- for( i=0, s= uid; i < uidlen && *s != '<'; s++, i++ )
- ;
- if( i < uidlen ) {
- /* skip opening delim and one char and look for the closing one*/
- s++; i++;
- for( se=s+1, i++; i < uidlen && *se != '>'; se++, i++ )
- ;
- if( i < uidlen ) {
- i = se - s;
- if( mode == 3 ) { /* exact email address */
- if( strlen(name)-2 == i
- && !ascii_memcasecmp( s, name+1, i) )
- return 0;
- }
- else if( mode == 4 ) { /* email substring */
- if( ascii_memistr( s, i, name ) )
- return 0;
- }
- else { /* email from end */
- /* nyi */
- }
- }
- }
- }
- else if( mode == 6 )
- return word_match( uid, uidlen, name );
- else
- BUG();
-
- return -1; /* not found */
-}
-
-
-
-
/************************************************
************* Merging stuff ********************
************************************************/
@@ -1446,14 +1256,8 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
/* see whether we have the MDC feature */
uid->mdc_feature = 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
- if (!p)
- n=0;
- for (; n; n--, p++) {
- if (*p == 1) {
- uid->mdc_feature = 1;
- break;
- }
- }
+ if (p && n && (p[0] & 0x01))
+ uid->mdc_feature = 1;
}
@@ -1936,8 +1740,9 @@ merge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
/* 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
+ * We need this function because we can't delete it later when we
* actually merge the secret parts into the pubring.
+ & The function also plays some games with the node flags.
*/
static void
premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
@@ -1948,6 +1753,7 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
assert ( secblock->pkt->pkttype == PKT_SECRET_KEY );
for (pub=pubblock,last=NULL; pub; last = pub, pub = pub->next ) {
+ pub->flag &= ~3; /* reset bits 0 and 1 */
if ( pub->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
KBNODE sec;
PKT_public_key *pk = pub->pkt->pkt.public_key;
@@ -1962,6 +1768,8 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
Fix the pubkey usage */
pk->pubkey_usage &= ~PUBKEY_USAGE_SIG;
}
+ /* transfer flag bits 0 and 1 to the pubblock */
+ pub->flag |= (sec->flag &3);
break;
}
}
@@ -1994,80 +1802,6 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
-/************************************************
- ************* Find stuff ***********************
- ************************************************/
-
-static PKT_user_id *
-find_by_name( KBNODE keyblock, const char *name, int mode )
-{
- KBNODE k;
-
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_USER_ID
- && !compare_name( k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len, name, mode)) {
- return k->pkt->pkt.user_id;
- }
- }
-
- return NULL;
-}
-
-
-
-static KBNODE
-find_by_keyid( KBNODE keyblock, u32 *keyid, int mode )
-{
- KBNODE k;
-
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- u32 aki[2];
- keyid_from_pk( k->pkt->pkt.public_key, aki );
- if( aki[1] == keyid[1] && ( mode == 10 || aki[0] == keyid[0] ) ) {
- return k; /* found */
- }
- }
- }
- return NULL;
-}
-
-
-
-static KBNODE
-find_by_fpr( KBNODE keyblock, const char *name, int mode )
-{
- KBNODE k;
-
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- byte afp[MAX_FINGERPRINT_LEN];
- size_t an;
-
- fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
- if ( 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;
- }
- }
- }
- }
- return NULL;
-}
-
-
-
-
/* See see whether the key fits
* our requirements and in case we do not
* request the primary key, we should select
@@ -2098,24 +1832,40 @@ find_by_fpr( KBNODE keyblock, const char *name, int mode )
*/
static int
-finish_lookup( GETKEY_CTX ctx, KBNODE foundk, PKT_user_id *foundu )
+finish_lookup (GETKEY_CTX ctx)
{
KBNODE keyblock = ctx->keyblock;
KBNODE k;
+ KBNODE foundk = NULL;
+ PKT_user_id *foundu = NULL;
#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC)
unsigned int req_usage = ( ctx->req_usage & USAGE_MASK );
u32 latest_date;
KBNODE latest_key;
u32 curtime = make_timestamp ();
- assert( !foundk || foundk->pkt->pkttype == PKT_PUBLIC_KEY
- || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY );
assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY );
ctx->found_key = NULL;
- if (!ctx->exact)
- foundk = NULL;
+ if (ctx->exact) {
+ for (k=keyblock; k; k = k->next) {
+ if ( (k->flag & 1) ) {
+ assert ( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+ foundk = k;
+ break;
+ }
+ }
+ }
+
+ for (k=keyblock; k; k = k->next) {
+ if ( (k->flag & 2) ) {
+ assert (k->pkt->pkttype == PKT_USER_ID);
+ foundu = k->pkt->pkt.user_id;
+ break;
+ }
+ }
if ( DBG_CACHE )
log_debug( "finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
@@ -2255,105 +2005,76 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk, PKT_user_id *foundu )
return 1; /* found */
}
-
+
static int
lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
{
int rc;
- int oldmode = set_packet_list_mode(0);
KBNODE secblock = NULL; /* helper */
int no_suitable_key = 0;
-
- if( !ctx->count ) /* first time */
- rc = enum_keyblocks( secmode? 5:0, &ctx->kbpos, NULL );
- else
- rc = 0;
- if( !rc ) {
- while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
- int n;
- getkey_item_t *item;
-
- if ( secmode ) {
- /* find the correspondig public key and use this
- * this one for the selection process */
- u32 aki[2];
- KBNODE k = ctx->keyblock;
-
- if ( k->pkt->pkttype != PKT_SECRET_KEY )
- BUG();
- keyid_from_sk( k->pkt->pkt.secret_key, aki );
- k = get_pubkeyblock( aki );
- if( !k ) {
- if (!opt.quiet)
- log_info(_("key %08lX: secret key without public key "
- "- skipped\n"), (ulong)aki[1] );
- goto skip;
- }
- secblock = ctx->keyblock;
- ctx->keyblock = k;
- premerge_public_with_secret ( ctx->keyblock, secblock );
+
+ rc = 0;
+ while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems))) {
+ rc = keydb_get_keyblock (ctx->kr_handle, &ctx->keyblock);
+ if (rc) {
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ rc = 0;
+ goto skip;
+ }
+
+ if ( secmode ) {
+ /* find the correspondig public key and use this
+ * this one for the selection process */
+ u32 aki[2];
+ KBNODE k = ctx->keyblock;
+
+ if (k->pkt->pkttype != PKT_SECRET_KEY)
+ BUG();
+
+ keyid_from_sk (k->pkt->pkt.secret_key, aki);
+ k = get_pubkeyblock (aki);
+ if( !k ) {
+ if (!opt.quiet)
+ log_info(_("key %08lX: secret key without public key "
+ "- skipped\n"), (ulong)aki[1] );
+ goto skip;
}
+ secblock = ctx->keyblock;
+ ctx->keyblock = k;
+ premerge_public_with_secret ( ctx->keyblock, secblock );
+ }
- /* loop over all the user ids we want to look for */
- item = ctx->items;
- for(n=0; n < ctx->nitems; n++, item++ ) {
- KBNODE k = NULL;
- int found = 0;
- PKT_user_id *found_uid = NULL;
-
- if( item->mode < 10 ) {
- found_uid = find_by_name( ctx->keyblock,
- item->name, item->mode );
- found = !!found_uid;
- }
- else if( item->mode >= 10 && item->mode <= 12 ) {
- k = find_by_keyid( ctx->keyblock,
- item->keyid, item->mode );
- found = !!k;
- }
- else if( item->mode == 15 ) {
- found = 1;
- }
- else if( item->mode == 16 || item->mode == 20
- || item->mode == 21 ) {
- k = find_by_fpr( ctx->keyblock,
- item->fprint, item->mode );
- found = !!k;
- }
- else
- BUG();
- if( found ) {
- /* this keyblock looks fine - do further investigation */
- merge_selfsigs ( ctx->keyblock );
- if ( finish_lookup( ctx, k, found_uid ) ) {
- no_suitable_key = 0;
- if ( secmode ) {
- merge_public_with_secret ( ctx->keyblock,
- secblock);
- release_kbnode (secblock);
- secblock = NULL;
- }
- goto found;
- }
- else
- no_suitable_key = 1;
- }
- }
- skip:
- /* release resources and try the next keyblock */
+ /* warning: node flag bits 0 and 1 should be preserved by
+ * merge_selfsigs. For secret keys, premerge did tranfer the
+ * keys to the keyblock */
+ merge_selfsigs ( ctx->keyblock );
+ if ( finish_lookup (ctx) ) {
+ no_suitable_key = 0;
if ( secmode ) {
- release_kbnode( secblock );
+ merge_public_with_secret ( ctx->keyblock,
+ secblock);
+ release_kbnode (secblock);
secblock = NULL;
}
- release_kbnode( ctx->keyblock );
- ctx->keyblock = NULL;
- }
- found:
- ;
+ goto found;
+ }
+ else
+ no_suitable_key = 1;
+
+ skip:
+ /* release resources and continue search */
+ if ( secmode ) {
+ release_kbnode( secblock );
+ secblock = NULL;
+ }
+ release_kbnode( ctx->keyblock );
+ ctx->keyblock = NULL;
}
+
+ found:
if( rc && rc != -1 )
- log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
+ log_error("enum_keyblocks_read failed: %s\n", g10_errstr(rc));
if( !rc ) {
*ret_keyblock = ctx->keyblock; /* return the keyblock */
@@ -2370,29 +2091,8 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
}
release_kbnode( ctx->keyblock );
ctx->keyblock = NULL;
- set_packet_list_mode(oldmode);
- #if 0
- if( opt.debug & DBG_MEMSTAT_VALUE ) {
- static int initialized;
-
- if( !initialized ) {
- initialized = 1;
- atexit( print_stats );
- }
-
- assert( ctx->mode < DIM(lkup_stats) );
- lkup_stats[ctx->mode].any = 1;
- if( !rc )
- lkup_stats[ctx->mode].okay_count++;
- else if ( rc == G10ERR_NO_PUBKEY || rc == G10ERR_NO_SECKEY )
- lkup_stats[ctx->mode].nokey_count++;
- else
- lkup_stats[ctx->mode].error_count++;
- }
- #endif
ctx->last_rc = rc;
- ctx->count++;
return rc;
}
@@ -2414,33 +2114,32 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
* to indicate EOF.
* 4) Always call this function a last time with SK set to NULL,
* so that can free it's context.
- *
- *
*/
int
enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
{
int rc=0;
- PACKET pkt;
- int save_mode;
struct {
int eof;
- int sequence;
- const char *name;
- IOBUF iobuf;
+ int first;
+ KEYDB_HANDLE hd;
+ KBNODE keyblock;
+ KBNODE node;
} *c = *context;
if( !c ) { /* make a new context */
c = m_alloc_clear( sizeof *c );
*context = c;
- c->sequence = 0;
- c->name = enum_keyblock_resources( &c->sequence, 1 );
+ c->hd = keydb_new (1);
+ c->first = 1;
+ c->keyblock = NULL;
+ c->node = NULL;
}
if( !sk ) { /* free the context */
- if( c->iobuf )
- iobuf_close(c->iobuf);
+ keydb_release (c->hd);
+ release_kbnode (c->keyblock);
m_free( c );
*context = NULL;
return 0;
@@ -2449,33 +2148,33 @@ enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
if( c->eof )
return -1;
- /* FIXME: This assumes a plain keyring file */
- for( ; c->name; c->name = enum_keyblock_resources( &c->sequence, 1 ) ) {
- if( !c->iobuf ) {
- if( !(c->iobuf = iobuf_open( c->name ) ) ) {
- log_error("enum_secret_keys: can't open `%s'\n", c->name );
- continue; /* try next file */
- }
- }
+ do {
+ /* get the next secret key from the current keyblock */
+ for (; c->node; c->node = c->node->next) {
+ if (c->node->pkt->pkttype == PKT_SECRET_KEY
+ || (with_subkeys
+ && c->node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
+ copy_secret_key (sk, c->node->pkt->pkt.secret_key );
+ c->node = c->node->next;
+ return 0; /* found */
+ }
+ }
+ release_kbnode (c->keyblock);
+ c->keyblock = c->node = NULL;
+
+ rc = c->first? keydb_search_first (c->hd) : keydb_search_next (c->hd);
+ c->first = 0;
+ if (rc) {
+ keydb_release (c->hd); c->hd = NULL;
+ c->eof = 1;
+ return -1; /* eof */
+ }
+
+ rc = keydb_get_keyblock (c->hd, &c->keyblock);
+ c->node = c->keyblock;
+ } while (!rc);
- save_mode = set_packet_list_mode(0);
- init_packet(&pkt);
- while( (rc=parse_packet(c->iobuf, &pkt)) != -1 ) {
- if( rc )
- ; /* e.g. unknown packet */
- else if( pkt.pkttype == PKT_SECRET_KEY
- || ( with_subkeys && pkt.pkttype == PKT_SECRET_SUBKEY ) ) {
- copy_secret_key( sk, pkt.pkt.secret_key );
- set_packet_list_mode(save_mode);
- return 0; /* found */
- }
- free_packet(&pkt);
- }
- set_packet_list_mode(save_mode);
- iobuf_close(c->iobuf); c->iobuf = NULL;
- }
- c->eof = 1;
- return -1;
+ return rc; /* error */
}
diff --git a/g10/global.h b/g10/global.h
new file mode 100644
index 000000000..3c4e59ec4
--- /dev/null
+++ b/g10/global.h
@@ -0,0 +1,29 @@
+/* global.h - Local typedefs and constants
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef GPG_GLOBAL_H
+#define GPG_GLOBAL_H
+
+#define MAX_FINGERPRINT_LEN 20
+
+typedef struct kbnode_struct *KBNODE;
+typedef struct keydb_search_desc KEYDB_SEARCH_DESC;
+
+#endif /*GPG_GLOBAL_H*/
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 64dcfe64b..7d0ecc86f 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -189,9 +189,9 @@ main( int argc, char **argv )
set_packet_list_mode(1);
if( !nrings ) /* no keyring given: use default one */
- add_keyblock_resource("trustedkeys" EXTSEP_S "gpg", 0, 0);
+ keydb_add_resource ("trustedkeys" EXTSEP_S "gpg", 0, 0);
for(sl = nrings; sl; sl = sl->next )
- add_keyblock_resource( sl->d, 0, 0 );
+ keydb_add_resource (sl->d, 0, 0 );
FREE_STRLIST(nrings);
diff --git a/g10/import.c b/g10/import.c
index c3a35aa8a..88abd30c1 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -379,7 +379,6 @@ import_one( const char *fname, KBNODE keyblock, int fast )
PKT_public_key *pk_orig;
KBNODE node, uidnode;
KBNODE keyblock_orig = NULL;
- KBPOS kbpos;
u32 keyid[2];
int rc = 0;
int new_key = 0;
@@ -443,21 +442,20 @@ import_one( const char *fname, KBNODE keyblock, int fast )
stats.skipped_new_keys++;
}
else if( rc ) { /* insert this key */
- /* get default resource */
- if( get_keyblock_handle( NULL, 0, &kbpos ) ) {
- log_error(_("no default public keyring\n"));
+ KEYDB_HANDLE hd = keydb_new (0);
+
+ rc = keydb_locate_writable (hd, NULL);
+ if (rc) {
+ log_error (_("no writable keyring found: %s\n"), g10_errstr (rc));
return G10ERR_GENERAL;
}
if( opt.verbose > 1 )
- log_info( _("writing to `%s'\n"),
- keyblock_resource_name(&kbpos) );
- if( (rc=lock_keyblock( &kbpos )) )
- log_error(_("can't lock keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- else if( (rc=insert_keyblock( &kbpos, keyblock )) )
- log_error( _("error writing keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- unlock_keyblock( &kbpos );
+ log_info (_("writing to `%s'\n"), keydb_get_resource_name (hd) );
+ rc = keydb_insert_keyblock (hd, keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc));
+ keydb_release (hd);
/* we are ready */
if( !opt.quiet )
log_info( _("key %08lX: public key imported\n"), (ulong)keyid[1]);
@@ -472,8 +470,10 @@ import_one( const char *fname, KBNODE keyblock, int fast )
new_key = 1;
}
else { /* merge */
+ KEYDB_HANDLE hd;
int n_uids, n_sigs, n_subk;
+
/* Compare the original against the new key; just to be sure nothing
* weird is going on */
if( cmp_public_keys( pk_orig, pk ) ) {
@@ -484,16 +484,27 @@ import_one( const char *fname, KBNODE keyblock, int fast )
}
/* now read the original keyblock */
- rc = find_keyblock_bypk( &kbpos, pk_orig );
+ hd = keydb_new (0);
+ {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk (pk_orig, afp, &an);
+ while (an < MAX_FINGERPRINT_LEN)
+ afp[an++] = 0;
+ rc = keydb_search_fpr (hd, afp);
+ }
if( rc ) {
- log_error( _("key %08lX: can't locate original keyblock: %s\n"),
+ log_error (_("key %08lX: can't locate original keyblock: %s\n"),
(ulong)keyid[1], g10_errstr(rc));
+ keydb_release (hd);
goto leave;
}
- rc = read_keyblock( &kbpos, &keyblock_orig );
- if( rc ) {
- log_error( _("key %08lX: can't read original keyblock: %s\n"),
+ rc = keydb_get_keyblock (hd, &keyblock_orig );
+ if (rc) {
+ log_error (_("key %08lX: can't read original keyblock: %s\n"),
(ulong)keyid[1], g10_errstr(rc));
+ keydb_release (hd);
goto leave;
}
@@ -504,18 +515,18 @@ import_one( const char *fname, KBNODE keyblock, int fast )
n_uids = n_sigs = n_subk = 0;
rc = merge_blocks( fname, keyblock_orig, keyblock,
keyid, &n_uids, &n_sigs, &n_subk );
- if( rc )
+ if( rc ) {
+ keydb_release (hd);
goto leave;
+ }
if( n_uids || n_sigs || n_subk ) {
mod_key = 1;
/* keyblock_orig has been updated; write */
- if( (rc=lock_keyblock( &kbpos )) )
- log_error( _("can't lock keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- else if( (rc=update_keyblock( &kbpos, keyblock_orig )) )
- log_error( _("error writing keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- unlock_keyblock( &kbpos );
+ rc = keydb_update_keyblock (hd, keyblock_orig);
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ keydb_release (hd); hd = NULL;
/* we are ready */
if( !opt.quiet ) {
if( n_uids == 1 )
@@ -582,7 +593,6 @@ import_secret_one( const char *fname, KBNODE keyblock, int allow )
{
PKT_secret_key *sk;
KBNODE node, uidnode;
- KBPOS kbpos;
u32 keyid[2];
int rc = 0;
@@ -623,18 +633,20 @@ import_secret_one( const char *fname, KBNODE keyblock, int allow )
/* do we have this key already in one of our secrings ? */
rc = seckey_available( keyid );
if( rc == G10ERR_NO_SECKEY && !opt.merge_only ) { /* simply insert this key */
+ KEYDB_HANDLE hd = keydb_new (1);
+
/* get default resource */
- if( get_keyblock_handle( NULL, 1, &kbpos ) ) {
- log_error("no default secret keyring\n");
+ rc = keydb_locate_writable (hd, NULL);
+ if (rc) {
+ log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
+ keydb_release (hd);
return G10ERR_GENERAL;
}
- if( (rc=lock_keyblock( &kbpos )) )
- log_error( _("can't lock keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- else if( (rc=insert_keyblock( &kbpos, keyblock )) )
- log_error( _("error writing keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- unlock_keyblock( &kbpos );
+ rc = keydb_insert_keyblock (hd, keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ keydb_release (hd);
/* we are ready */
if( !opt.quiet )
log_info( _("key %08lX: secret key imported\n"), (ulong)keyid[1]);
@@ -661,7 +673,7 @@ import_revoke_cert( const char *fname, KBNODE node )
{
PKT_public_key *pk=NULL;
KBNODE onode, keyblock = NULL;
- KBPOS kbpos;
+ KEYDB_HANDLE hd = NULL;
u32 keyid[2];
int rc = 0;
@@ -687,16 +699,25 @@ import_revoke_cert( const char *fname, KBNODE node )
}
/* read the original keyblock */
- rc = find_keyblock_bypk( &kbpos, pk );
- if( rc ) {
- log_error( _("key %08lX: can't locate original keyblock: %s\n"),
- (ulong)keyid[1], g10_errstr(rc));
+ hd = keydb_new (0);
+ {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk (pk, afp, &an);
+ while (an < MAX_FINGERPRINT_LEN)
+ afp[an++] = 0;
+ rc = keydb_search_fpr (hd, afp);
+ }
+ if (rc) {
+ log_error (_("key %08lX: can't locate original keyblock: %s\n"),
+ (ulong)keyid[1], g10_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], g10_errstr(rc));
+ rc = keydb_get_keyblock (hd, &keyblock );
+ if (rc) {
+ log_error (_("key %08lX: can't read original keyblock: %s\n"),
+ (ulong)keyid[1], g10_errstr(rc));
goto leave;
}
@@ -729,13 +750,11 @@ import_revoke_cert( const char *fname, KBNODE node )
insert_kbnode( keyblock, clone_kbnode(node), 0 );
/* and write the keyblock back */
- if( (rc=lock_keyblock( &kbpos )) )
- log_error( _("can't lock keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- else if( (rc=update_keyblock( &kbpos, keyblock )) )
- log_error( _("error writing keyring `%s': %s\n"),
- keyblock_resource_name(&kbpos), g10_errstr(rc) );
- unlock_keyblock( &kbpos );
+ rc = keydb_update_keyblock (hd, keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ keydb_release (hd); hd = NULL;
/* we are ready */
if( !opt.quiet )
log_info( _("key %08lX: revocation certificate imported\n"),
@@ -752,6 +771,7 @@ import_revoke_cert( const char *fname, KBNODE node )
}
leave:
+ keydb_release (hd);
release_kbnode( keyblock );
free_public_key( pk );
return rc;
diff --git a/g10/keydb.c b/g10/keydb.c
new file mode 100644
index 000000000..e26a6f75a
--- /dev/null
+++ b/g10/keydb.c
@@ -0,0 +1,623 @@
+/* keydb.c - key database dispatcher
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "options.h"
+#include "main.h" /*try_make_homedir ()*/
+#include "packet.h"
+#include "keyring.h"
+#include "keydb.h"
+#include "i18n.h"
+
+static int active_handles;
+
+typedef enum {
+ KEYDB_RESOURCE_TYPE_NONE = 0,
+ KEYDB_RESOURCE_TYPE_KEYRING
+} KeydbResourceType;
+#define MAX_KEYDB_RESOURCES 1
+
+struct resource_item {
+ KeydbResourceType type;
+ union {
+ KEYRING_HANDLE kr;
+ } u;
+};
+
+
+struct keydb_handle {
+ int locked;
+ int found;
+ int current;
+ struct resource_item active[MAX_KEYDB_RESOURCES];
+};
+
+
+static int lock_all (KEYDB_HANDLE hd);
+static void unlock_all (KEYDB_HANDLE hd);
+
+
+/*
+ * Register a resource (which currently may only be a keyring file).
+ * The first keyring which is added by this function is
+ * created if it does not exist.
+ * Note: this function may be called before secure memory is
+ * available.
+ */
+int
+keydb_add_resource (const char *url, int force, int secret)
+{
+ static int any_secret, any_public;
+ const char *resname = url;
+ IOBUF iobuf = NULL;
+ char *filename = NULL;
+ int rc = 0;
+ KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
+ const char *created_fname = NULL;
+
+ /* Do we have an URL?
+ * gnupg-ring:filename := this is a plain keyring
+ * filename := See what is is, but create as plain keyring.
+ */
+ if (strlen (resname) > 11) {
+ if (!strncmp( resname, "gnupg-ring:", 11) ) {
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ resname += 11;
+ }
+ #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
+ else if (strchr (resname, ':')) {
+ log_error ("invalid key resource URL `%s'\n", url );
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+ #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
+ }
+
+ if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
+ if (strchr(resname, DIRSEP_C) )
+ filename = make_filename (resname, NULL);
+ else
+ filename = make_filename (opt.homedir, resname, NULL);
+ }
+ else
+ filename = m_strdup (resname);
+
+ if (!force)
+ force = secret? !any_secret : !any_public;
+
+ /* see whether we can determine the filetype */
+ if (rt == KEYDB_RESOURCE_TYPE_NONE) {
+ FILE *fp = fopen( filename, "rb" );
+
+ if (fp) {
+ u32 magic;
+
+ if (fread( &magic, 4, 1, fp) == 1 ) {
+ if (magic == 0x13579ace || magic == 0xce9a5713)
+ ; /* GDBM magic - no more support */
+ else
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ }
+ else /* maybe empty: assume ring */
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ fclose( fp );
+ }
+ else /* no file yet: create ring */
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ }
+
+ switch (rt) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ log_error ("unknown type of key resource `%s'\n", url );
+ rc = G10ERR_GENERAL;
+ goto leave;
+
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ iobuf = iobuf_open (filename);
+ if (!iobuf && !force) {
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+
+ if (!iobuf) {
+ char *last_slash_in_filename;
+
+ last_slash_in_filename = strrchr (filename, DIRSEP_C);
+ *last_slash_in_filename = 0;
+
+ if (access(filename, F_OK)) {
+ /* on the first time we try to create the default homedir and
+ * in this case the process will be terminated, so that on the
+ * next invocation it can read the options file in on startup
+ */
+ try_make_homedir (filename);
+ rc = G10ERR_OPEN_FILE;
+ *last_slash_in_filename = DIRSEP_C;
+ goto leave;
+ }
+
+ *last_slash_in_filename = DIRSEP_C;
+
+ iobuf = iobuf_create (filename);
+ if (!iobuf) {
+ log_error ( _("error creating keyring `%s': %s\n"),
+ filename, strerror(errno));
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+ else {
+ #ifndef HAVE_DOSISH_SYSTEM
+ if (secret && !opt.preserve_permissions) {
+ if (chmod (filename, S_IRUSR | S_IWUSR) ) {
+ log_error (_("changing permission of "
+ " `%s' failed: %s\n"),
+ filename, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ #endif
+ if (!opt.quiet)
+ log_info (_("keyring `%s' created\n"), filename);
+ created_fname = filename;
+ }
+ }
+ iobuf_close (iobuf);
+ iobuf = NULL;
+ if (created_fname) /* must invalidate that ugly cache */
+ iobuf_ioctl (NULL, 2, 0, (char*)created_fname);
+ keyring_register_filename (filename, secret);
+ break;
+
+ default:
+ log_error ("resource type of `%s' not supported\n", url);
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+
+ /* fixme: check directory permissions and print a warning */
+
+ leave:
+ if (rc)
+ log_error ("keyblock resource `%s': %s\n", filename, g10_errstr(rc));
+ else if (secret)
+ any_secret = 1;
+ else
+ any_public = 1;
+ m_free (filename);
+ return rc;
+}
+
+
+
+
+KEYDB_HANDLE
+keydb_new (int secret)
+{
+ KEYDB_HANDLE hd;
+ int i=0;
+
+ hd = m_alloc_clear (sizeof *hd);
+ hd->found = -1;
+
+ hd->active[i].type = KEYDB_RESOURCE_TYPE_KEYRING;
+ hd->active[i].u.kr = keyring_new (secret);
+ if (!hd->active[i].u.kr) {
+ m_free (hd);
+ return NULL;
+ }
+ i++;
+
+
+ assert (i <= MAX_KEYDB_RESOURCES);
+ active_handles++;
+ return hd;
+}
+
+void
+keydb_release (KEYDB_HANDLE hd)
+{
+ int i;
+
+ if (!hd)
+ return;
+ assert (active_handles > 0);
+ active_handles--;
+
+ unlock_all (hd);
+ for (i=0; i < MAX_KEYDB_RESOURCES; i++) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ keyring_release (hd->active[i].u.kr);
+ break;
+ }
+ }
+
+ m_free (hd);
+}
+
+
+/*
+ * Return the name of the current resource. This is function first
+ * looks for the last found found, then for the current search
+ * position, and last returns the first available resource. The
+ * returned string is only valid as long as the handle exists. This
+ * function does only return NULL if no handle is specified, in all
+ * other error cases an empty string is returned.
+ */
+const char *
+keydb_get_resource_name (KEYDB_HANDLE hd)
+{
+ int idx;
+ const char *s = NULL;
+
+ if (!hd)
+ return NULL;
+
+ if ( hd->found >= 0 && hd->found < MAX_KEYDB_RESOURCES)
+ idx = hd->found;
+ else if ( hd->current >= 0 && hd->current < MAX_KEYDB_RESOURCES)
+ idx = hd->current;
+ else
+ idx = 0;
+
+ switch (hd->active[idx].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ s = NULL;
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ s = keyring_get_resource_name (hd->active[idx].u.kr);
+ break;
+ }
+
+ return s? s: "";
+}
+
+
+
+static int
+lock_all (KEYDB_HANDLE hd)
+{
+ int i, rc = 0;
+
+ for (i=0; !rc && i < MAX_KEYDB_RESOURCES; i++) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_lock (hd->active[i].u.kr, 1);
+ break;
+ }
+ }
+
+ if (rc) {
+ /* revert the alreadt set locks */
+ for (i--; i >= 0; i--) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ keyring_lock (hd->active[i].u.kr, 0);
+ break;
+ }
+ }
+ }
+ else
+ hd->locked = 1;
+
+ return rc;
+}
+
+static void
+unlock_all (KEYDB_HANDLE hd)
+{
+ int i;
+
+ if (!hd->locked)
+ return;
+
+ for (i=MAX_KEYDB_RESOURCES-1; i >= 0; i--) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ keyring_lock (hd->active[i].u.kr, 0);
+ break;
+ }
+ }
+ hd->locked = 0;
+}
+
+
+/*
+ * Return the last found keyring. Caller must free it.
+ * The returned keyblock has the kbode flag bit 0 set for the node with
+ * the public key used to locate the keyblock or flag bit 1 set for
+ * the user ID node.
+ */
+int
+keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
+{
+ int rc = 0;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if ( hd->found < 0 || hd->found >= MAX_KEYDB_RESOURCES)
+ return -1; /* nothing found */
+
+ switch (hd->active[hd->found].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * update the current keyblock with KB
+ */
+int
+keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb)
+{
+ int rc = 0;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if ( hd->found < 0 || hd->found >= MAX_KEYDB_RESOURCES)
+ return -1; /* nothing found */
+
+ if( opt.dry_run )
+ return 0;
+
+ rc = lock_all (hd);
+ if (rc)
+ return rc;
+
+ switch (hd->active[hd->found].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
+ break;
+ }
+
+ unlock_all (hd);
+ return rc;
+}
+
+
+/*
+ * Insert a new KB into one of the resources.
+ */
+int
+keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb)
+{
+ int rc = -1;
+ int idx;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if( opt.dry_run )
+ return 0;
+
+ if ( hd->found >= 0 && hd->found < MAX_KEYDB_RESOURCES)
+ idx = hd->found;
+ else if ( hd->current >= 0 && hd->current < MAX_KEYDB_RESOURCES)
+ idx = hd->current;
+ else
+ return G10ERR_GENERAL;
+
+ rc = lock_all (hd);
+ if (rc)
+ return rc;
+
+ switch (hd->active[idx].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
+ break;
+ }
+
+ unlock_all (hd);
+ return rc;
+}
+
+
+/*
+ * The current keyblock will be deleted.
+ */
+int
+keydb_delete_keyblock (KEYDB_HANDLE hd)
+{
+ int rc = -1;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if ( hd->found < 0 || hd->found >= MAX_KEYDB_RESOURCES)
+ return -1; /* nothing found */
+
+ if( opt.dry_run )
+ return 0;
+
+ rc = lock_all (hd);
+ if (rc)
+ return rc;
+
+ switch (hd->active[hd->found].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
+ break;
+ }
+
+ unlock_all (hd);
+ return rc;
+}
+
+
+/*
+ * Locate the default writable key resource, so that the next
+ * operation (which is only releavnt for inserts) will be onde on this
+ * resource.
+ */
+int
+keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
+{
+ int rc;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ rc = keydb_search_reset (hd);
+ if (!rc) {
+ /* fixme: set forward to a writable one */
+ }
+ return rc;
+}
+
+
+/*
+ * Start the next search on this handle right at the beginning
+ */
+int
+keydb_search_reset (KEYDB_HANDLE hd)
+{
+ int i, rc = 0;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ hd->current = 0;
+ hd->found = -1;
+ /* and reset all resources */
+ for (i=0; !rc && i < MAX_KEYDB_RESOURCES; i++) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_search_reset (hd->active[i].u.kr);
+ break;
+ }
+ }
+ return rc;
+}
+
+
+/*
+ * Search through all keydb resources, starting at the current position,
+ * for a keyblock which contains one of the keys described in the DESC array.
+ */
+int
+keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
+{
+ int rc = -1;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ while (rc == -1 && hd->current >= 0 && hd->current < MAX_KEYDB_RESOURCES) {
+ switch (hd->active[hd->current].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = -1; /* no resource = eof */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_search (hd->active[hd->current].u.kr, desc, ndesc);
+ break;
+ }
+ if (rc == -1) /* EOF -> switch to next resource */
+ hd->current++;
+ else if (!rc)
+ hd->found = hd->current;
+ }
+
+ return rc;
+}
+
+
+int
+keydb_search_first (KEYDB_HANDLE hd)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FIRST;
+ return keydb_search (hd, &desc, 1);
+}
+
+int
+keydb_search_next (KEYDB_HANDLE hd)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_NEXT;
+ return keydb_search (hd, &desc, 1);
+}
+
+int
+keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
+ desc.u.kid[0] = kid[0];
+ desc.u.kid[1] = kid[1];
+ return keydb_search (hd, &desc, 1);
+}
+
+int
+keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FPR;
+ memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
+ return keydb_search (hd, &desc, 1);
+}
+
+
+
diff --git a/g10/keydb.h b/g10/keydb.h
index 8438a3f9d..7d20b65c5 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -21,15 +21,11 @@
#ifndef G10_KEYDB_H
#define G10_KEYDB_H
-#ifdef HAVE_LIBGDBM
- #include <gdbm.h>
-#endif
-
#include "types.h"
+#include "global.h"
#include "packet.h"
#include "cipher.h"
-#define MAX_FINGERPRINT_LEN 20
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
@@ -50,7 +46,6 @@ typedef struct getkey_ctx_s *GETKEY_CTX;
* This structure is also used to bind arbitrary packets together.
*/
-typedef struct kbnode_struct *KBNODE;
struct kbnode_struct {
KBNODE next;
PACKET *pkt;
@@ -65,8 +60,7 @@ struct kbnode_struct {
enum resource_type {
rt_UNKNOWN = 0,
- rt_RING = 1,
- rt_GDBM = 2
+ rt_RING = 1
};
@@ -81,10 +75,6 @@ struct keyblock_pos_struct {
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;
};
@@ -118,6 +108,52 @@ struct pubkey_find_info {
};
+typedef struct keydb_handle *KEYDB_HANDLE;
+
+typedef enum {
+ KEYDB_SEARCH_MODE_NONE,
+ KEYDB_SEARCH_MODE_EXACT,
+ KEYDB_SEARCH_MODE_SUBSTR,
+ KEYDB_SEARCH_MODE_MAIL,
+ KEYDB_SEARCH_MODE_MAILSUB,
+ KEYDB_SEARCH_MODE_MAILEND,
+ KEYDB_SEARCH_MODE_WORDS,
+ KEYDB_SEARCH_MODE_SHORT_KID,
+ KEYDB_SEARCH_MODE_LONG_KID,
+ KEYDB_SEARCH_MODE_TDBIDX,
+ KEYDB_SEARCH_MODE_FPR16,
+ KEYDB_SEARCH_MODE_FPR20,
+ KEYDB_SEARCH_MODE_FPR,
+ KEYDB_SEARCH_MODE_FIRST,
+ KEYDB_SEARCH_MODE_NEXT
+} KeydbSearchMode;
+
+struct keydb_search_desc {
+ KeydbSearchMode mode;
+ union {
+ const char *name;
+ char fpr[MAX_FINGERPRINT_LEN];
+ u32 kid[2];
+ } u;
+};
+
+/*-- keydb.c --*/
+int keydb_add_resource (const char *url, int force, int secret);
+KEYDB_HANDLE keydb_new (int secret);
+void keydb_release (KEYDB_HANDLE hd);
+const char *keydb_get_resource_name (KEYDB_HANDLE hd);
+int keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
+int keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb);
+int keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb);
+int keydb_delete_keyblock (KEYDB_HANDLE hd);
+int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved);
+int keydb_search_reset (KEYDB_HANDLE hd);
+int keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
+int keydb_search_first (KEYDB_HANDLE hd);
+int keydb_search_next (KEYDB_HANDLE hd);
+int keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
+int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
+
/*-- pkclist.c --*/
int check_signatures_trust( PKT_signature *sig );
@@ -147,8 +183,8 @@ void cache_public_key( PKT_public_key *pk );
void getkey_disable_caches(void);
int get_pubkey( PKT_public_key *pk, u32 *keyid );
KBNODE get_pubkeyblock( u32 *keyid );
-int get_pubkey_byname( GETKEY_CTX *rx, PKT_public_key *pk,
- const char *name, KBNODE *ret_keyblock );
+int get_pubkey_byname( PKT_public_key *pk, const char *name,
+ KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd);
int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk,
STRLIST names, KBNODE *ret_keyblock );
int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
@@ -213,25 +249,4 @@ void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root );
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 );
-char *get_writable_keyblock_file( 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_secret_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk );
-int find_secret_keyblock_byname( KBPOS *kbpos, const char *username );
-int find_secret_keyblock_direct (KBPOS *kbpos, u32 *keyid);
-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 );
-
-
#endif /*G10_KEYDB_H*/
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 875e229e0..033220de1 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -84,30 +84,6 @@ struct sign_attrib {
-static int
-get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
-{
- int rc;
-
- *keyblock = NULL;
- /* search the userid */
- rc = find_keyblock_byname( kbpos, username );
- if( rc ) {
- log_error(_("%s: user not found\n"), username );
- return rc;
- }
-
- /* read the keyblock */
- rc = read_keyblock( kbpos, keyblock );
- if( rc )
- log_error("%s: keyblock read problem: %s\n", username, g10_errstr(rc));
- else
- merge_keys_and_selfsig( *keyblock );
-
- return rc;
-}
-
-
/****************
* Print information about a signature, check it and return true
* if the signature is okay. NODE must be a signature packet.
@@ -626,9 +602,9 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
enum cmdids cmd = 0;
int rc = 0;
KBNODE keyblock = NULL;
- KBPOS keyblockpos;
+ KEYDB_HANDLE kdbhd = NULL;
KBNODE sec_keyblock = NULL;
- KBPOS sec_keyblockpos;
+ KEYDB_HANDLE sec_kdbhd = NULL;
KBNODE cur_keyblock;
char *answer = NULL;
int redisplay = 1;
@@ -651,7 +627,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
}
/* get the public key */
- rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
+ rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd);
if( rc )
goto leave;
if( fix_keyblock( keyblock ) )
@@ -662,18 +638,34 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
if( !sign_mode ) {/* see whether we have a matching secret key */
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
- rc = find_secret_keyblock_bypk( &sec_keyblockpos, pk );
- if( !rc ) {
- rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
- if( rc ) {
- log_error("%s: secret keyblock read problem: %s\n",
+ sec_kdbhd = keydb_new (1);
+ {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk (pk, afp, &an);
+ while (an < MAX_FINGERPRINT_LEN)
+ afp[an++] = 0;
+ rc = keydb_search_fpr (sec_kdbhd, afp);
+ }
+ if (!rc) {
+ rc = keydb_get_keyblock (sec_kdbhd, &sec_keyblock);
+ if (rc) {
+ log_error (_("error reading secret keyblock `%s': %s\n"),
username, g10_errstr(rc));
- goto leave;
}
- merge_keys_and_selfsig( sec_keyblock );
- if( fix_keyblock( sec_keyblock ) )
- sec_modified++;
+ else {
+ merge_keys_and_selfsig( sec_keyblock );
+ if( fix_keyblock( sec_keyblock ) )
+ sec_modified++;
+ }
}
+
+ if (rc) {
+ sec_keyblock = NULL;
+ keydb_release (sec_kdbhd); sec_kdbhd = NULL;
+ rc = 0;
+ }
}
if( sec_keyblock ) {
@@ -1012,23 +1004,24 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
do_cmd_save:
if( modified || sec_modified ) {
if( modified ) {
- rc = update_keyblock( &keyblockpos, keyblock );
+ rc = keydb_update_keyblock (kdbhd, keyblock);
if( rc ) {
log_error(_("update failed: %s\n"), g10_errstr(rc) );
break;
}
}
if( sec_modified ) {
- rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
+ rc = keydb_update_keyblock (sec_kdbhd, sec_keyblock );
if( rc ) {
- log_error(_("update secret failed: %s\n"),
- g10_errstr(rc) );
+ log_error( _("update secret failed: %s\n"),
+ g10_errstr(rc) );
break;
}
}
}
else
tty_printf(_("Key not changed so no update needed.\n"));
+
/* TODO: we should keep track whether we have changed
* something relevant to the trustdb */
if( !modified && sign_mode )
@@ -1051,6 +1044,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
leave:
release_kbnode( keyblock );
release_kbnode( sec_keyblock );
+ keydb_release (kdbhd);
m_free(answer);
}
diff --git a/g10/keygen.c b/g10/keygen.c
index 37d4a0740..8a29d7711 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -284,22 +284,22 @@ static void
add_feature_mdc (PKT_signature *sig)
{
const byte *s;
- size_t i, n;
+ size_t n;
char *buf;
s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
- if (!s)
- n = 0;
-
- for (i=0; i < n; i++ ) {
- if (s[i] == 1)
- return; /* already set */
+ if (s && n && (s[0] & 0x01))
+ return; /* already set */
+ if (!s || !n) { /* create a new one */
+ n = 1;
+ buf = m_alloc (n);
}
-
- buf = m_alloc (n+1);
- buf[0] = 1; /* MDC feature */
- memcpy (buf+1, s, n);
- build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n+1);
+ else {
+ buf = m_alloc (n);
+ memcpy (buf, s, n);
+ }
+ buf[0] |= 0x01; /* MDC feature */
+ build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
m_free (buf);
}
@@ -1769,8 +1769,6 @@ static void
do_generate_keypair( struct para_data_s *para,
struct output_control_s *outctrl )
{
- char *pub_fname = NULL;
- char *sec_fname = NULL;
KBNODE pub_root = NULL;
KBNODE sec_root = NULL;
PKT_secret_key *sk = NULL;
@@ -1823,20 +1821,14 @@ do_generate_keypair( struct para_data_s *para,
&outctrl->sec.afx );
}
}
- pub_fname = outctrl->pub.fname; /* only for info output */
- sec_fname = outctrl->sec.fname; /* only for info output */
assert( outctrl->pub.stream );
assert( outctrl->sec.stream );
- }
- else {
- pub_fname = get_writable_keyblock_file( 0 );
- sec_fname = get_writable_keyblock_file( 1 );
+ if( opt.verbose ) {
+ log_info(_("writing public key to `%s'\n"), outctrl->pub.fname );
+ log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
+ }
}
- if( opt.verbose ) {
- log_info(_("writing public key to `%s'\n"), pub_fname );
- log_info(_("writing secret key to `%s'\n"), sec_fname );
- }
/* we create the packets as a tree of kbnodes. Because the structure
* we create is known in advance we simply generate a linked list
@@ -1895,46 +1887,47 @@ do_generate_keypair( struct para_data_s *para,
}
else if( !rc ) { /* write to the standard keyrings */
- KBPOS pub_kbpos;
- KBPOS sec_kbpos;
- int rc1 = -1;
- int rc2 = -1;
-
- /* we can now write the certificates */
- if( get_keyblock_handle( pub_fname, 0, &pub_kbpos ) ) {
- if( add_keyblock_resource( pub_fname, 1, 0 ) ) {
- log_error("can add keyblock file `%s'\n", pub_fname );
- rc = G10ERR_CREATE_FILE;
- }
- else if( get_keyblock_handle( pub_fname, 0, &pub_kbpos ) ) {
- log_error("can get keyblock handle for `%s'\n", pub_fname );
- rc = G10ERR_CREATE_FILE;
- }
- }
- if( rc )
- ;
- else if( get_keyblock_handle( sec_fname, 1, &sec_kbpos ) ) {
- if( add_keyblock_resource( sec_fname, 1, 1 ) ) {
- log_error("can add keyblock file `%s'\n", sec_fname );
- rc = G10ERR_CREATE_FILE;
- }
- else if( get_keyblock_handle( sec_fname, 1, &sec_kbpos ) ) {
- log_error("can get keyblock handle for `%s'\n", sec_fname );
- rc = G10ERR_CREATE_FILE;
- }
- }
+ KEYDB_HANDLE pub_hd = keydb_new (0);
+ KEYDB_HANDLE sec_hd = keydb_new (1);
+
+ /* FIXME: we may have to create the keyring first */
+ rc = keydb_locate_writable (pub_hd, NULL);
+ if (rc)
+ log_error (_("no writable public keyring found: %s\n"),
+ g10_errstr (rc));
+
+ if (!rc) {
+ rc = keydb_locate_writable (sec_hd, NULL);
+ if (rc)
+ log_error (_("no writable secret keyring found: %s\n"),
+ g10_errstr (rc));
+ }
- if( rc )
- ;
- else if( (rc=rc1=lock_keyblock( &pub_kbpos )) )
- log_error("can't lock public keyring: %s\n", g10_errstr(rc) );
- else if( (rc=rc2=lock_keyblock( &sec_kbpos )) )
- log_error("can't lock secret keyring: %s\n", g10_errstr(rc) );
- else if( (rc=insert_keyblock( &pub_kbpos, pub_root )) )
- log_error("can't write public key: %s\n", g10_errstr(rc) );
- else if( (rc=insert_keyblock( &sec_kbpos, sec_root )) )
- log_error("can't write secret key: %s\n", g10_errstr(rc) );
- else {
+ if (!rc && opt.verbose) {
+ log_info(_("writing public key to `%s'\n"),
+ keydb_get_resource_name (pub_hd));
+ log_info(_("writing secret key to `%s'\n"),
+ keydb_get_resource_name (sec_hd));
+ }
+
+ if (!rc) {
+ rc = keydb_insert_keyblock (pub_hd, pub_root);
+ if (rc)
+ log_error (_("error writing public keyring `%s': %s\n"),
+ keydb_get_resource_name (pub_hd), g10_errstr(rc));
+ }
+
+ if (!rc) {
+ rc = keydb_insert_keyblock (sec_hd, sec_root);
+ if (rc)
+ log_error (_("error writing secret keyring `%s': %s\n"),
+ keydb_get_resource_name (pub_hd), g10_errstr(rc));
+ }
+
+ keydb_release (pub_hd);
+ keydb_release (sec_hd);
+
+ if (!rc) {
int no_enc_rsa =
get_parameter_algo(para, pKEYTYPE) == PUBKEY_ALGO_RSA
&& get_parameter_uint( para, pKEYUSAGE )
@@ -1953,11 +1946,6 @@ do_generate_keypair( struct para_data_s *para,
"secondary key for this purpose.\n") );
}
}
-
- if( !rc1 )
- unlock_keyblock( &pub_kbpos );
- if( !rc2 )
- unlock_keyblock( &sec_kbpos );
}
if( rc ) {
@@ -1973,10 +1961,6 @@ do_generate_keypair( struct para_data_s *para,
release_kbnode( sec_root );
if( sk ) /* the unprotected secret key */
free_secret_key(sk);
- if( !outctrl->use_files ) {
- m_free(pub_fname);
- m_free(sec_fname);
- }
}
diff --git a/g10/keyid.c b/g10/keyid.c
index b933e7ab8..59f3883c0 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -277,7 +277,7 @@ mk_datestr (char *buffer, time_t atime)
struct tm *tp;
if ( atime < 0 ) /* 32 bit time_t and after 2038-01-19 */
- strcpy (buffer, "????-??-??"); /* mark this as invalid */
+ strcpy (buffer, "????" "-??" "-??"); /* mark this as invalid */
else {
tp = gmtime (&atime);
sprintf (buffer,"%04d-%02d-%02d",
@@ -401,9 +401,9 @@ byte *
fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len )
{
byte *p, *buf;
- const char *dp;
+ const byte *dp;
size_t len;
- unsigned n;
+ unsigned int n;
if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
/* RSA in version 3 packets is special */
@@ -434,6 +434,8 @@ fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len )
if( !array )
array = m_alloc( len );
memcpy(array, dp, len );
+ pk->keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
+ pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
md_close(md);
}
diff --git a/g10/keylist.c b/g10/keylist.c
index f445d67b6..01f208d8c 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -67,41 +67,50 @@ secret_key_list( STRLIST list )
static void
list_all( int secret )
{
- KBPOS kbpos;
+ KEYDB_HANDLE hd;
KBNODE keyblock = NULL;
int rc=0;
- int lastresno;
+ const char *lastresname, *resname;
- rc = enum_keyblocks( secret? 5:0, &kbpos, &keyblock );
+ hd = keydb_new (secret);
+ if (!hd)
+ rc = G10ERR_GENERAL;
+ else
+ rc = keydb_search_first (hd);
if( rc ) {
if( rc != -1 )
- log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) );
+ log_error("keydb_search_first failed: %s\n", g10_errstr(rc) );
goto leave;
}
- lastresno = -1;
- while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
- if( lastresno != kbpos.resno ) {
- const char *s = keyblock_resource_name( &kbpos );
+ lastresname = NULL;
+ do {
+ rc = keydb_get_keyblock (hd, &keyblock);
+ if (rc) {
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+ resname = keydb_get_resource_name (hd);
+ if (lastresname != resname ) {
int i;
- lastresno = kbpos.resno;
- printf("%s\n", s );
- for(i=strlen(s); i; i-- )
+ printf("%s\n", resname );
+ for(i=strlen(resname); i; i-- )
putchar('-');
putchar('\n');
+ lastresname = resname;
}
merge_keys_and_selfsig( keyblock );
list_keyblock( keyblock, secret );
- release_kbnode( keyblock ); keyblock = NULL;
- }
-
+ release_kbnode( keyblock );
+ keyblock = NULL;
+ } while (!(rc = keydb_search_next (hd)));
if( rc && rc != -1 )
- log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc));
+ log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
leave:
- enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
- release_kbnode( keyblock );
+ release_kbnode (keyblock);
+ keydb_release (hd);
}
diff --git a/g10/keyring.c b/g10/keyring.c
new file mode 100644
index 000000000..c63f02b84
--- /dev/null
+++ b/g10/keyring.c
@@ -0,0 +1,1061 @@
+/* keyring.c - keyring file handling
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "keyring.h"
+#include "packet.h"
+#include "keydb.h"
+#include "options.h"
+#include "i18n.h"
+
+typedef struct keyring_name *KR_NAME;
+struct keyring_name {
+ struct keyring_name *next;
+ int secret;
+ DOTLOCK lockhd;
+ int is_locked;
+ char fname[1];
+};
+typedef struct keyring_name const * CONST_KR_NAME;
+
+static KR_NAME kr_names;
+static int active_handles;
+
+struct keyring_handle {
+ int secret; /* this is for a secret keyring */
+ struct {
+ CONST_KR_NAME kr;
+ IOBUF iobuf;
+ int eof;
+ int error;
+ } current;
+ struct {
+ CONST_KR_NAME kr;
+ off_t offset;
+ size_t pk_no;
+ size_t uid_no;
+ unsigned int n_packets; /*used for delete and update*/
+ } found;
+ struct {
+ char *name;
+ char *pattern;
+ } word_match;
+};
+
+static int do_copy (int mode, const char *fname, KBNODE root, int secret,
+ off_t start_offset, unsigned int n_packets );
+
+
+
+/*
+ * Register a filename for plain keyring files
+ */
+void
+keyring_register_filename (const char *fname, int secret)
+{
+ KR_NAME kr;
+
+ if (active_handles)
+ BUG (); /* We don't allow that */
+
+ for (kr=kr_names; kr; kr = kr->next) {
+ if ( !compare_filenames (kr->fname, fname) )
+ return; /* already registered */
+ }
+
+ kr = m_alloc (sizeof *kr + strlen (fname));
+ strcpy (kr->fname, fname);
+ kr->secret = !!secret;
+ kr->lockhd = NULL;
+ kr->is_locked = 0;
+ kr->next = kr_names;
+ kr_names = kr;
+}
+
+
+
+
+
+KEYRING_HANDLE
+keyring_new (int secret)
+{
+ KEYRING_HANDLE hd;
+
+ hd = m_alloc_clear (sizeof *hd);
+ hd->secret = !!secret;
+ active_handles++;
+ return hd;
+}
+
+void
+keyring_release (KEYRING_HANDLE hd)
+{
+ if (!hd)
+ return;
+ assert (active_handles > 0);
+ active_handles--;
+ m_free (hd->word_match.name);
+ m_free (hd->word_match.pattern);
+ m_free (hd);
+}
+
+static CONST_KR_NAME
+next_kr (CONST_KR_NAME start, int secret)
+{
+ start = start? start->next : kr_names;
+ while ( start && start->secret != secret )
+ start = start->next;
+ return start;
+}
+
+const char *
+keyring_get_resource_name (KEYRING_HANDLE hd)
+{
+ const char *fname;
+
+ if (!hd)
+ fname = NULL;
+ else if (hd->found.kr)
+ fname = hd->found.kr->fname;
+ else if (hd->current.kr)
+ fname = hd->current.kr->fname;
+ else {
+ CONST_KR_NAME kr = next_kr (NULL, hd->secret);
+ fname = kr? kr->fname:NULL;
+ }
+
+ return fname;
+}
+
+
+/*
+ * Lock the keyring with the given handle, or unlok if yes is false.
+ * We ignore the handle and lock all registered files.
+ */
+int
+keyring_lock (KEYRING_HANDLE hd, int yes)
+{
+ KR_NAME kr;
+ int rc = 0;
+
+ if (yes) {
+ /* first make sure the lock handles are created */
+ for (kr=kr_names; kr; kr = kr->next) {
+ if (!kr->lockhd) {
+ kr->lockhd = create_dotlock( kr->fname );
+ if (!kr->lockhd) {
+ log_info ("can't allocate lock for `%s'\n", kr->fname );
+ rc = G10ERR_GENERAL;
+ }
+ }
+ }
+ if (rc)
+ return rc;
+
+ /* and now set the locks */
+ for (kr=kr_names; kr; kr = kr->next) {
+ if (kr->is_locked)
+ ;
+ else if (make_dotlock (kr->lockhd, -1) ) {
+ log_info ("can't lock `%s'\n", kr->fname );
+ rc = G10ERR_GENERAL;
+ }
+ else
+ kr->is_locked = 1;
+ }
+ }
+
+ if (rc || !yes) {
+ for (kr=kr_names; kr; kr = kr->next) {
+ if (!kr->is_locked)
+ ;
+ else if (release_dotlock (kr->lockhd))
+ log_info ("can't unlock `%s'\n", kr->fname );
+ else
+ kr->is_locked = 0;
+ }
+ }
+
+ return rc;
+}
+
+
+
+/*
+ * Return the last found keyring. Caller must free it.
+ * The returned keyblock has the kbode flag bit 0 set for the node with
+ * the public key used to locate the keyblock or flag bit 1 set for
+ * the user ID node.
+ */
+int
+keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
+{
+ PACKET *pkt;
+ int rc;
+ KBNODE keyblock = NULL, node;
+ IOBUF a;
+ int in_cert = 0;
+ int pk_no = 0;
+ int uid_no = 0;
+
+ if (!hd->found.kr)
+ return -1; /* no successful search */
+
+ a = iobuf_open (hd->found.kr->fname);
+ if (!a) {
+ log_error ("can't open `%s'\n", hd->found.kr->fname);
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ if (iobuf_seek (a, hd->found.offset) ) {
+ log_error ("can't seek `%s'\n", hd->found.kr->fname);
+ iobuf_close(a);
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ pkt = m_alloc (sizeof *pkt);
+ init_packet (pkt);
+ hd->found.n_packets = 0;;
+ while ((rc=parse_packet (a, pkt)) != -1) {
+ hd->found.n_packets++;
+ if (rc == G10ERR_UNKNOWN_PACKET) {
+ free_packet (pkt);
+ init_packet (pkt);
+ continue;
+ }
+ if (rc) {
+ log_error ("keyring_get_keyblock: read error: %s\n",
+ g10_errstr(rc) );
+ rc = G10ERR_INV_KEYRING;
+ break;
+ }
+ if (pkt->pkttype == PKT_COMPRESSED) {
+ log_error ("skipped compressed packet in keyring\n");
+ free_packet(pkt);
+ init_packet(pkt);
+ continue;
+ }
+
+ if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
+ || pkt->pkttype == PKT_SECRET_KEY)) {
+ hd->found.n_packets--; /* fix counter */
+ break; /* ready */
+ }
+
+ in_cert = 1;
+ node = new_kbnode (pkt);
+ if (!keyblock)
+ keyblock = node;
+ else
+ add_kbnode (keyblock, node);
+
+ if ( pkt->pkttype == PKT_PUBLIC_KEY
+ || pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || pkt->pkttype == PKT_SECRET_KEY
+ || pkt->pkttype == PKT_SECRET_SUBKEY) {
+ if (++pk_no == hd->found.pk_no)
+ node->flag |= 1;
+ }
+ else if ( pkt->pkttype == PKT_USER_ID) {
+ if (++uid_no == hd->found.uid_no)
+ node->flag |= 2;
+ }
+
+ pkt = m_alloc (sizeof *pkt);
+ init_packet(pkt);
+ }
+
+ if (rc == -1 && keyblock)
+ rc = 0; /* got the entire keyblock */
+
+ if (rc || !ret_kb)
+ release_kbnode (keyblock);
+ else
+ *ret_kb = keyblock;
+
+ free_packet (pkt);
+ m_free (pkt);
+ iobuf_close(a);
+ return rc;
+}
+
+int
+keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
+{
+ int rc;
+
+ if (!hd->found.kr)
+ return -1; /* no successful prior search */
+
+ if (!hd->found.n_packets) {
+ /* need to know the number of packets - do a dummy get_keyblock*/
+ rc = keyring_get_keyblock (hd, NULL);
+ if (rc) {
+ log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
+ return rc;
+ }
+ if (!hd->found.n_packets)
+ BUG ();
+ }
+
+ /* do the update */
+ rc = do_copy (3, hd->found.kr->fname, kb, hd->secret,
+ hd->found.offset, hd->found.n_packets );
+ if (!rc) {
+ /* better reset the found info */
+ hd->found.kr = NULL;
+ hd->found.offset = 0;
+ }
+ return rc;
+}
+
+int
+keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
+{
+ int rc;
+ const char *fname;
+
+ if (!hd)
+ fname = NULL;
+ else if (hd->found.kr)
+ fname = hd->found.kr->fname;
+ else if (hd->current.kr)
+ fname = hd->current.kr->fname;
+ else {
+ CONST_KR_NAME kr = next_kr (NULL, hd->secret);
+ fname = kr? kr->fname:NULL;
+ }
+
+ if (!fname)
+ return G10ERR_GENERAL;
+
+ /* do the insert */
+ rc = do_copy (1, fname, kb, hd->secret, 0, 0 );
+ return rc;
+}
+
+int
+keyring_delete_keyblock (KEYRING_HANDLE hd)
+{
+ int rc;
+
+ if (!hd->found.kr)
+ return -1; /* no successful prior search */
+
+ if (!hd->found.n_packets) {
+ /* need to know the number of packets - do a dummy get_keyblock*/
+ rc = keyring_get_keyblock (hd, NULL);
+ if (rc) {
+ log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
+ return rc;
+ }
+ if (!hd->found.n_packets)
+ BUG ();
+ }
+
+ /* do the delete */
+ rc = do_copy (2, hd->found.kr->fname, NULL, hd->secret,
+ hd->found.offset, hd->found.n_packets );
+ if (!rc) {
+ /* better reset the found info */
+ hd->found.kr = NULL;
+ hd->found.offset = 0;
+ }
+ return rc;
+}
+
+
+
+/*
+ * Start the next search on this handle right at the beginning
+ */
+int
+keyring_search_reset (KEYRING_HANDLE hd)
+{
+ assert (hd);
+
+ hd->current.kr = NULL;
+ iobuf_close (hd->current.iobuf);
+ hd->current.iobuf = NULL;
+ hd->current.eof = 0;
+ hd->current.error = 0;
+
+ hd->found.kr = NULL;
+ hd->found.offset = 0;
+ return 0;
+}
+
+
+static int
+prepare_search (KEYRING_HANDLE hd)
+{
+ if (hd->current.error)
+ return hd->current.error; /* still in error state */
+
+ if (hd->current.kr && !hd->current.eof) {
+ assert ( hd->current.iobuf);
+ return 0; /* okay */
+ }
+
+ if (!hd->current.kr && hd->current.eof)
+ return -1; /* still EOF */
+
+ if (!hd->current.kr) { /* start search with first keyring */
+ hd->current.kr = next_kr (NULL, hd->secret);
+ if (!hd->current.kr) {
+ hd->current.eof = 1;
+ return -1; /* no keyring available */
+ }
+ assert (!hd->current.iobuf);
+ }
+ else { /* EOF on last keyring - switch to next one */
+ iobuf_close (hd->current.iobuf);
+ hd->current.iobuf = NULL;
+ hd->current.kr = next_kr (hd->current.kr, hd->secret);
+ if (!hd->current.kr) {
+ hd->current.eof = 1;
+ return -1;
+ }
+ }
+
+ hd->current.eof = 0;
+ hd->current.iobuf = iobuf_open (hd->current.kr->fname);
+ if (!hd->current.iobuf) {
+ log_error ("can't open `%s'\n", hd->current.kr->fname );
+ return (hd->current.error = G10ERR_OPEN_FILE);
+ }
+
+ return 0;
+}
+
+
+/* A map of the all characters valid used for word_match()
+ * Valid characters are in in this table converted to uppercase.
+ * 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
+ * EBCDIC character set (user ids are UTF-8).
+ * wk 2000-04-13: Hmmm, does this really make sense, given the fact that
+ * we can run gpg now on a S/390 running GNU/Linux, where the code
+ * translation is done by the device drivers?
+ */
+static const byte word_match_chars[256] = {
+ /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 40 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ /* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ /* 58 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 60 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 68 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ /* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ /* 78 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /* 88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ /* 90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ /* 98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ /* a0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ /* a8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ /* b0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ /* b8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ /* c0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ /* c8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ /* d0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ /* d8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ /* e0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ /* e8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ /* f0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ /* f8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+/****************
+ * Do a word match (original user id starts with a '+').
+ * The pattern is already tokenized to a more suitable format:
+ * There are only the real words in it delimited by one space
+ * and all converted to uppercase.
+ *
+ * Returns: 0 if all words match.
+ *
+ * Note: This algorithm is a straightforward one and not very
+ * fast. It works for UTF-8 strings. The uidlen should
+ * be removed but due to the fact that old versions of
+ * pgp don't use UTF-8 we still use the length; this should
+ * be fixed in parse-packet (and replace \0 by some special
+ * UTF-8 encoding)
+ */
+static int
+word_match( const byte *uid, size_t uidlen, const byte *pattern )
+{
+ size_t wlen, n;
+ const byte *p;
+ const byte *s;
+
+ for( s=pattern; *s; ) {
+ do {
+ /* skip leading delimiters */
+ while( uidlen && !word_match_chars[*uid] )
+ uid++, uidlen--;
+ /* get length of the word */
+ n = uidlen; p = uid;
+ while( n && word_match_chars[*p] )
+ p++, n--;
+ wlen = p - uid;
+ /* and compare against the current word from pattern */
+ for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
+ if( word_match_chars[*p] != s[n] )
+ break;
+ }
+ if( n == wlen && (s[n] == ' ' || !s[n]) )
+ break; /* found */
+ uid += wlen;
+ uidlen -= wlen;
+ } while( uidlen );
+ if( !uidlen )
+ return -1; /* not found */
+
+ /* advance to next word in pattern */
+ for(; *s != ' ' && *s ; s++ )
+ ;
+ if( *s )
+ s++ ;
+ }
+ return 0; /* found */
+}
+
+/****************
+ * prepare word word_match; that is parse the name and
+ * build the pattern.
+ * caller has to free the returned pattern
+ */
+static char*
+prepare_word_match (const byte *name)
+{
+ byte *pattern, *p;
+ int c;
+
+ /* the original length is always enough for the pattern */
+ p = pattern = m_alloc(strlen(name)+1);
+ do {
+ /* skip leading delimiters */
+ while( *name && !word_match_chars[*name] )
+ name++;
+ /* copy as long as we don't have a delimiter and convert
+ * to uppercase.
+ * fixme: how can we handle utf8 uppercasing */
+ for( ; *name && (c=word_match_chars[*name]); name++ )
+ *p++ = c;
+ *p++ = ' '; /* append pattern delimiter */
+ } while( *name );
+ p[-1] = 0; /* replace last pattern delimiter by EOS */
+
+ return pattern;
+}
+
+
+
+
+static int
+compare_name (int mode, const char *name, const char *uid, size_t uidlen)
+{
+ int i;
+ const char *s, *se;
+
+ if (mode == KEYDB_SEARCH_MODE_EXACT) {
+ for (i=0; name[i] && uidlen; i++, uidlen--)
+ if (uid[i] != name[i])
+ break;
+ if (!uidlen && !name[i])
+ return 0; /* found */
+ }
+ else if (mode == KEYDB_SEARCH_MODE_SUBSTR) {
+ if (ascii_memistr( uid, uidlen, name ))
+ return 0;
+ }
+ else if ( mode == KEYDB_SEARCH_MODE_MAIL
+ || mode == KEYDB_SEARCH_MODE_MAILSUB
+ || mode == KEYDB_SEARCH_MODE_MAILEND) {
+ for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
+ ;
+ if (i < uidlen) {
+ /* skip opening delim and one char and look for the closing one*/
+ s++; i++;
+ for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
+ ;
+ if (i < uidlen) {
+ i = se - s;
+ if (mode == KEYDB_SEARCH_MODE_MAIL) {
+ if( strlen(name)-2 == i
+ && !ascii_memcasecmp( s, name+1, i) )
+ return 0;
+ }
+ else if (mode == KEYDB_SEARCH_MODE_MAILSUB) {
+ if( ascii_memistr( s, i, name ) )
+ return 0;
+ }
+ else { /* email from end */
+ /* nyi */
+ }
+ }
+ }
+ }
+ else if (mode == KEYDB_SEARCH_MODE_WORDS)
+ return word_match (uid, uidlen, name);
+ else
+ BUG();
+
+ return -1; /* not found */
+}
+
+
+/*
+ * Search through the keyring(s), starting at the current position,
+ * for a keyblock which contains one of the keys described in the DESC array.
+ */
+int
+keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
+{
+ int rc;
+ PACKET pkt;
+ int save_mode;
+ off_t offset, main_offset;
+ size_t n;
+ int need_uid, need_words, need_keyid, need_fpr;
+ int pk_no, uid_no;
+ int initial_skip;
+ PKT_user_id *uid = NULL;
+ PKT_public_key *pk = NULL;
+ PKT_secret_key *sk = NULL;
+
+ /* figure out what information we need */
+ need_uid = need_words = need_keyid = need_fpr = 0;
+ for (n=0; n < ndesc; n++) {
+ switch (desc[n].mode) {
+ case KEYDB_SEARCH_MODE_EXACT:
+ case KEYDB_SEARCH_MODE_SUBSTR:
+ case KEYDB_SEARCH_MODE_MAIL:
+ case KEYDB_SEARCH_MODE_MAILSUB:
+ case KEYDB_SEARCH_MODE_MAILEND:
+ need_uid = 1;
+ break;
+ case KEYDB_SEARCH_MODE_WORDS:
+ need_uid = 1;
+ need_words = 1;
+ break;
+ case KEYDB_SEARCH_MODE_SHORT_KID:
+ case KEYDB_SEARCH_MODE_LONG_KID:
+ need_keyid = 1;
+ break;
+ case KEYDB_SEARCH_MODE_FPR16:
+ case KEYDB_SEARCH_MODE_FPR20:
+ case KEYDB_SEARCH_MODE_FPR:
+ need_fpr = 1;
+ break;
+ case KEYDB_SEARCH_MODE_FIRST:
+ /* always restart the search in this mode */
+ keyring_search_reset (hd);
+ break;
+ default: break;
+ }
+ }
+
+ rc = prepare_search (hd);
+ if (rc)
+ return rc;
+
+#if 0
+ if (need_words) {
+ BUG();
+ if ( !hd->word_match.name || strcmp (hd->word_match.name, name) ) {
+ /* name changed */
+ m_free (hd->word_match.name);
+ m_free (hd->word_match.pattern);
+ hd->word_match.name = m_strdup (name);
+ hd->word_match.pattern = prepare_word_match (name);
+ }
+ name = hd->word_match.pattern;
+ }
+#endif
+
+ init_packet(&pkt);
+ save_mode = set_packet_list_mode(0);
+
+ hd->found.kr = NULL;
+ main_offset = 0;
+ pk_no = uid_no = 0;
+ initial_skip = 1; /* skip until we see the start of a keyblock */
+ while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid))) {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+ u32 aki[2];
+
+ if (pkt.pkttype == PKT_PUBLIC_KEY
+ || pkt.pkttype == PKT_SECRET_KEY) {
+ main_offset = offset;
+ pk_no = uid_no = 0;
+ initial_skip = 0;
+ }
+ if (initial_skip) {
+ free_packet (&pkt);
+ continue;
+ }
+
+ pk = NULL;
+ sk = NULL;
+ uid = NULL;
+ if ( pkt.pkttype == PKT_PUBLIC_KEY
+ || pkt.pkttype == PKT_PUBLIC_SUBKEY) {
+ pk = pkt.pkt.public_key;
+ ++pk_no;
+
+ if (need_fpr) {
+ fingerprint_from_pk (pk, afp, &an);
+ while (an < 20) /* fill up to 20 bytes */
+ afp[an++] = 0;
+ }
+ if (need_keyid)
+ keyid_from_pk (pk, aki);
+ }
+ else if (pkt.pkttype == PKT_USER_ID) {
+ uid = pkt.pkt.user_id;
+ ++uid_no;
+ }
+ else if ( pkt.pkttype == PKT_SECRET_KEY
+ || pkt.pkttype == PKT_SECRET_SUBKEY) {
+ sk = pkt.pkt.secret_key;
+ ++pk_no;
+
+ if (need_fpr) {
+ fingerprint_from_sk (sk, afp, &an);
+ while (an < 20) /* fill up to 20 bytes */
+ afp[an++] = 0;
+ }
+ if (need_keyid)
+ keyid_from_sk (sk, aki);
+ }
+
+ for (n=0; n < ndesc; n++) {
+ switch (desc[n].mode) {
+ case KEYDB_SEARCH_MODE_NONE:
+ BUG ();
+ break;
+ case KEYDB_SEARCH_MODE_TDBIDX:
+ BUG();
+ break;
+ case KEYDB_SEARCH_MODE_EXACT:
+ case KEYDB_SEARCH_MODE_SUBSTR:
+ case KEYDB_SEARCH_MODE_MAIL:
+ case KEYDB_SEARCH_MODE_MAILSUB:
+ case KEYDB_SEARCH_MODE_MAILEND:
+ case KEYDB_SEARCH_MODE_WORDS:
+ if ( uid && !compare_name (desc[n].mode,
+ desc[n].u.name,
+ uid->name, uid->len))
+ goto found;
+ break;
+
+ case KEYDB_SEARCH_MODE_SHORT_KID:
+ if ((pk||sk) && desc[n].u.kid[1] == aki[1])
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_LONG_KID:
+ if ((pk||sk) && desc[n].u.kid[0] == aki[0]
+ && desc[n].u.kid[1] == aki[1])
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_FPR16: break;
+ if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 16))
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_FPR20:
+ case KEYDB_SEARCH_MODE_FPR:
+ if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20))
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_FIRST:
+ case KEYDB_SEARCH_MODE_NEXT:
+ if (pk||sk)
+ goto found;
+ break;
+ default:
+ rc = G10ERR_INV_ARG;
+ goto found;
+ }
+ }
+
+ free_packet (&pkt);
+ }
+ found:
+ if( !rc ) {
+ hd->found.offset = main_offset;
+ hd->found.kr = hd->current.kr;
+ hd->found.pk_no = (pk||sk)? pk_no : 0;
+ hd->found.uid_no = uid? uid_no : 0;
+ }
+ else if (rc == -1)
+ hd->current.eof = 1;
+ else
+ hd->current.error = rc;
+
+ free_packet(&pkt);
+ set_packet_list_mode(save_mode);
+ return rc;
+}
+
+
+
+/****************
+ * Perform insert/delete/update operation.
+ * mode 1 = insert
+ * 2 = delete
+ * 3 = update
+ */
+static int
+do_copy (int mode, const char *fname, KBNODE root, int secret,
+ off_t start_offset, unsigned int n_packets )
+{
+ IOBUF fp, newfp;
+ int rc=0;
+ char *bakfname = NULL;
+ char *tmpfname = NULL;
+
+ /* open the source file */
+ fp = iobuf_open (fname);
+ if (mode == 1 && !fp && errno == ENOENT) {
+ /* insert mode but file does not exist: create a new file */
+ KBNODE kbctx, node;
+
+ newfp = iobuf_create (fname);
+ if( !newfp ) {
+ log_error (_("%s: can't create: %s\n"),
+ fname, strerror(errno));
+ return G10ERR_OPEN_FILE;
+ }
+ if( !opt.quiet )
+ log_info(_("%s: keyring created\n"), fname );
+
+ kbctx=NULL;
+ while ( (node = walk_kbnode( root, &kbctx, 0 )) ) {
+ if( (rc = build_packet( newfp, node->pkt )) ) {
+ log_error("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, g10_errstr(rc) );
+ iobuf_cancel(newfp);
+ return G10ERR_WRITE_FILE;
+ }
+ }
+ if( iobuf_close(newfp) ) {
+ log_error ("%s: close failed: %s\n", fname, strerror(errno));
+ return G10ERR_CLOSE_FILE;
+ }
+ if (chmod( fname, S_IRUSR | S_IWUSR )) {
+ log_error("%s: chmod failed: %s\n", fname, strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ return 0; /* ready */
+ }
+
+ if( !fp ) {
+ log_error ("%s: can't open: %s\n", fname, strerror(errno) );
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+
+ /* create the new file */
+ #ifdef USE_ONLY_8DOT3
+ /* Here is another Windoze bug?:
+ * you cant rename("pubring.gpg.tmp", "pubring.gpg");
+ * but rename("pubring.gpg.tmp", "pubring.aaa");
+ * works. So we replace .gpg by .bak or .tmp
+ */
+ if( strlen (fname) > 4
+ && !strcmp (fname+strlen(fname)-4, EXTSEP_S "gpg") ) {
+ bakfname = m_alloc( strlen (fname) + 1 );
+ strcpy(bakfname, fname);
+ strcpy(bakfname+strlen(fname)-4, EXTSEP_S "bak");
+ tmpfname = m_alloc( strlen( fname ) + 1 );
+ strcpy(tmpfname,fname);
+ strcpy(tmpfname+strlen(fname)-4, EXTSEP_S "tmp");
+ }
+ else { /* file does not end with gpg; hmmm */
+ bakfname = m_alloc( strlen( fname ) + 5 );
+ strcpy(stpcpy(bakfname, fname), EXTSEP_S "bak");
+ tmpfname = m_alloc( strlen( fname ) + 5 );
+ strcpy(stpcpy(tmpfname, fname), EXTSEP_S "tmp");
+ }
+ #else
+ bakfname = m_alloc( strlen( fname ) + 2 );
+ strcpy(stpcpy(bakfname,fname),"~");
+ tmpfname = m_alloc( strlen( fname ) + 5 );
+ strcpy(stpcpy(tmpfname,fname), EXTSEP_S "tmp");
+ #endif
+ newfp = iobuf_create (tmpfname);
+ if (!newfp) {
+ log_error ("%s: can't create: %s\n", tmpfname, strerror(errno) );
+ iobuf_close(fp);
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+
+ if( mode == 1 ) { /* insert */
+ /* copy everything to the new file */
+ rc = copy_all_packets (fp, newfp);
+ if( rc != -1 ) {
+ log_error("%s: copy to `%s' failed: %s\n",
+ fname, tmpfname, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ rc = 0;
+ }
+
+ if( mode == 2 || mode == 3 ) { /* delete or update */
+ /* copy first part to the new file */
+ rc = copy_some_packets( fp, newfp, start_offset );
+ if( rc ) { /* should never get EOF here */
+ log_error ("%s: copy to `%s' failed: %s\n",
+ fname, tmpfname, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ /* skip this keyblock */
+ assert( n_packets );
+ rc = skip_some_packets( fp, n_packets );
+ if( rc ) {
+ log_error("%s: skipping %u packets failed: %s\n",
+ fname, n_packets, g10_errstr(rc));
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ }
+
+ if( mode == 1 || mode == 3 ) { /* insert or update */
+ KBNODE kbctx, node;
+
+ /* append the new data */
+ kbctx=NULL;
+ while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
+ if( (rc = build_packet( newfp, node->pkt )) ) {
+ log_error("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ }
+
+ if( mode == 2 || mode == 3 ) { /* delete or update */
+ /* copy the rest */
+ rc = copy_all_packets( fp, newfp );
+ if( rc != -1 ) {
+ log_error("%s: copy to `%s' failed: %s\n",
+ fname, tmpfname, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ rc = 0;
+ }
+
+ /* close both files */
+ if( iobuf_close(fp) ) {
+ log_error("%s: close failed: %s\n", fname, strerror(errno) );
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ if( iobuf_close(newfp) ) {
+ log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ /* if the new file is a secring, restrict the permissions */
+ #ifndef HAVE_DOSISH_SYSTEM
+ if( secret && !opt.preserve_permissions ) {
+ if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
+ log_error("%s: chmod failed: %s\n",
+ tmpfname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ #endif
+
+ /* rename and make backup file */
+ if( !secret ) { /* but not for secret keyrings */
+ iobuf_ioctl (NULL, 2, 0, (char *)bakfname );
+ iobuf_ioctl (NULL, 2, 0, (char *)fname );
+ #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ remove( bakfname );
+ #endif
+ if( rename( fname, bakfname ) ) {
+ log_error("%s: rename to `%s' failed: %s\n",
+ fname, bakfname, strerror(errno) );
+ rc = G10ERR_RENAME_FILE;
+ goto leave;
+ }
+ }
+ iobuf_ioctl (NULL, 2, 0, (char*)tmpfname );
+ iobuf_ioctl (NULL, 2, 0, (char*)fname );
+ #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ remove( fname );
+ #endif
+ if( rename( tmpfname, fname ) ) {
+ log_error("%s: rename to `%s' failed: %s\n",
+ tmpfname, fname,strerror(errno) );
+ rc = G10ERR_RENAME_FILE;
+ if( secret ) {
+ log_info(_(
+ "WARNING: 2 files with confidential information exists.\n"));
+ log_info(_("%s is the unchanged one\n"), fname );
+ log_info(_("%s is the new one\n"), tmpfname );
+ log_info(_("Please fix this possible security flaw\n"));
+ }
+ goto leave;
+ }
+
+ leave:
+ m_free(bakfname);
+ m_free(tmpfname);
+ return rc;
+}
+
+
+
+
+
diff --git a/g10/keyring.h b/g10/keyring.h
new file mode 100644
index 000000000..253b86eab
--- /dev/null
+++ b/g10/keyring.h
@@ -0,0 +1,44 @@
+/* keyring.h - Keyring operations
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef GPG_KEYRING_H
+#define GPG_KEYRING_H 1
+
+#include "global.h"
+
+
+typedef struct keyring_handle *KEYRING_HANDLE;
+
+void keyring_register_filename (const char *fname, int secret);
+
+
+KEYRING_HANDLE keyring_new (int secret);
+void keyring_release (KEYRING_HANDLE hd);
+const char *keyring_get_resource_name (KEYRING_HANDLE hd);
+int keyring_lock (KEYRING_HANDLE hd, int yes);
+int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb);
+int keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb);
+int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb);
+int keyring_delete_keyblock (KEYRING_HANDLE hd);
+int keyring_search_reset (KEYRING_HANDLE hd);
+int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
+
+
+#endif /*GPG_KEYRING_H*/
diff --git a/g10/keyring.o b/g10/keyring.o
new file mode 100644
index 000000000..e0a98900d
--- /dev/null
+++ b/g10/keyring.o
Binary files differ
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 9023168b2..20a9b98d0 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -755,7 +755,7 @@ print_notation_data( PKT_signature *sig )
write_status_buffer ( STATUS_POLICY_URL, p, n, 0 );
}
- /* Now check wheter the key of this signature has some
+ /* Now check whether the key of this signature has some
* notation data */
/* TODO */
diff --git a/g10/options.h b/g10/options.h
index 43b547c24..dc691693f 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -50,6 +50,7 @@ struct {
int check_sigs; /* check key signatures */
int with_colons;
int with_key_data;
+ int with_fingerprint; /* opt --with-fingerprint active */
int fingerprint; /* list fingerprints */
int list_sigs; /* list signatures */
int no_armor;
diff --git a/g10/packet.h b/g10/packet.h
index 5e4e89ea0..d3e7ddd91 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -323,7 +323,7 @@ int list_packets( IOBUF a );
int set_packet_list_mode( int mode );
#if DEBUG_PARSE_PACKET
-int dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos,
+int dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid,
const char* file, int lineno );
int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt,
const char* file, int lineno );
@@ -333,8 +333,8 @@ int dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t 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 ) \
- dbg_search_packet( (a), (b), (c), __FILE__, __LINE__ )
+#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 copy_all_packets( a,b ) \
@@ -344,7 +344,7 @@ int dbg_skip_some_packets( IOBUF inp, unsigned n,
#define skip_some_packets( a,b ) \
dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
#else
-int search_packet( IOBUF inp, PACKET *pkt, off_t *retpos );
+int search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid );
int parse_packet( IOBUF inp, PACKET *ret_pkt);
int copy_all_packets( IOBUF inp, IOBUF out );
int copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff );
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 96bebd243..2292f9fd2 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -158,24 +158,24 @@ parse_packet( IOBUF inp, PACKET *pkt )
*/
#ifdef DEBUG_PARSE_PACKET
int
-dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos,
+dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid,
const char *dbg_f, int dbg_l )
{
int skip, rc;
do {
- rc = parse( inp, pkt, 1, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
+ rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
} while( skip );
return rc;
}
#else
int
-search_packet( IOBUF inp, PACKET *pkt, off_t *retpos )
+search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid )
{
int skip, rc;
do {
- rc = parse( inp, pkt, 1, retpos, &skip, NULL, 0 );
+ rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0 );
} while( skip );
return rc;
}
@@ -296,6 +296,7 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
byte hdr[8];
int hdrlen;
int new_ctb = 0;
+ int with_uid = (onlykeypkts == 2);
*skip = 0;
assert( !pkt->pkt.generic );
@@ -309,7 +310,7 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
hdrlen=0;
hdr[hdrlen++] = ctb;
if( !(ctb & 0x80) ) {
- log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb );
+ log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb );
rc = G10ERR_INVALID_PACKET;
goto leave;
}
@@ -375,12 +376,14 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
goto leave;
}
- if( do_skip
+ if (with_uid && pkttype == PKT_USER_ID)
+ ;
+ else if( do_skip
|| !pkttype
|| (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY
&& pkttype != PKT_PUBLIC_KEY
&& pkttype != PKT_SECRET_SUBKEY
- && pkttype != PKT_SECRET_KEY ) ) {
+ && pkttype != PKT_SECRET_KEY ) ) {
skip_rest(inp, pktlen);
*skip = 1;
rc = 0;
@@ -866,7 +869,7 @@ dump_sig_subpkt( int hashed, int type, int critical,
case SIGSUBPKT_FEATURES:
fputs ( "features:", stdout );
for( i=0; i < length; i++ )
- printf(" %d", buffer[i] );
+ printf(" %02x", buffer[i] );
break;
case SIGSUBPKT_PRIV_VERIFY_CACHE:
p = "verification cache";
diff --git a/g10/passphrase.c b/g10/passphrase.c
index c6c7cb27d..7ca28e72a 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -285,7 +285,7 @@ agent_get_passphrase ( u32 *keyid, int mode )
char *atext;
char buf[50];
int fd = -1;
- int nread;
+ size_t nread;
u32 reply;
char *pw = NULL;
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
@@ -433,7 +433,7 @@ passphrase_clear_cache ( u32 *keyid, int algo )
size_t n;
char buf[50];
int fd = -1;
- int nread;
+ size_t nread;
u32 reply;
PKT_public_key *pk;
byte fpr[MAX_FINGERPRINT_LEN];
diff --git a/g10/pkclist.c b/g10/pkclist.c
index e4e0f38a3..e09d55418 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -628,7 +628,10 @@ check_signatures_trust( PKT_signature *sig )
if( opt.always_trust ) {
if( !opt.quiet )
log_info(_("WARNING: Using untrusted key!\n"));
- return 0;
+ if (opt.with_fingerprint)
+ fpr_info (pk);
+ rc = 0;
+ goto leave;
}
@@ -705,6 +708,8 @@ check_signatures_trust( PKT_signature *sig )
write_status( STATUS_TRUST_NEVER );
log_info(_("WARNING: We do NOT trust this key!\n"));
log_info(_(" The signature is probably a FORGERY.\n"));
+ if (opt.with_fingerprint)
+ fpr_info (pk);
rc = G10ERR_BAD_SIGN;
break;
@@ -721,10 +726,14 @@ check_signatures_trust( PKT_signature *sig )
case TRUST_FULLY:
write_status( STATUS_TRUST_FULLY );
+ if (opt.with_fingerprint)
+ fpr_info (pk);
break;
case TRUST_ULTIMATE:
write_status( STATUS_TRUST_ULTIMATE );
+ if (opt.with_fingerprint)
+ fpr_info (pk);
break;
default: BUG();
@@ -814,10 +823,12 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
else if( (use & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to ) {
pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- if( (rc = get_pubkey_byname( NULL, pk, rov->d, NULL )) ) {
+ if( (rc = get_pubkey_byname( pk, rov->d, NULL, NULL )) ) {
free_public_key( pk ); pk = NULL;
log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
- }
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ rov->d, strlen (rov->d), -1);
+ }
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
/* Skip the actual key if the key is already present
* in the list */
@@ -838,6 +849,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
else {
free_public_key( pk ); pk = NULL;
log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ rov->d, strlen (rov->d), -1);
}
}
}
@@ -870,7 +883,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
free_public_key( pk );
pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- rc = get_pubkey_byname( NULL, pk, answer, NULL );
+ rc = get_pubkey_byname( pk, answer, NULL, NULL );
if( rc )
tty_printf(_("No such user ID.\n"));
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
@@ -936,7 +949,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
else if( !any_recipients && (def_rec = default_recipient()) ) {
pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- rc = get_pubkey_byname( NULL, pk, def_rec, NULL );
+ rc = get_pubkey_byname( pk, def_rec, NULL, NULL );
if( rc )
log_error(_("unknown default recipient `%s'\n"), def_rec );
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
@@ -961,9 +974,12 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- if( (rc = get_pubkey_byname( NULL, pk, remusr->d, NULL )) ) {
+ if( (rc = get_pubkey_byname( pk, remusr->d, NULL, NULL )) ) {
free_public_key( pk ); pk = NULL;
log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d, strlen (remusr->d),
+ -1);
}
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
int trustlevel;
@@ -973,11 +989,19 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
free_public_key( pk ); pk = NULL;
log_error(_("%s: error checking key: %s\n"),
remusr->d, g10_errstr(rc) );
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d,
+ strlen (remusr->d),
+ -1);
}
else if( (trustlevel & TRUST_FLAG_DISABLED) ) {
free_public_key(pk); pk = NULL;
log_info(_("%s: skipped: public key is disabled\n"),
remusr->d);
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d,
+ strlen (remusr->d),
+ -1);
}
else if( do_we_trust_pre( pk, trustlevel ) ) {
/* note: do_we_trust may have changed the trustlevel */
@@ -1004,10 +1028,18 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
}
else { /* we don't trust this pk */
free_public_key( pk ); pk = NULL;
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d,
+ strlen (remusr->d),
+ -1);
}
}
else {
free_public_key( pk ); pk = NULL;
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d,
+ strlen (remusr->d),
+ -1);
log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
}
}
diff --git a/g10/revoke.c b/g10/revoke.c
index 7e25aeaa2..10db123cd 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -87,41 +87,46 @@ gen_revoke( const char *uname )
IOBUF out = NULL;
KBNODE keyblock = NULL;
KBNODE node;
- KBPOS kbpos;
+ KEYDB_HANDLE kdbhd;
struct revocation_reason_info *reason = NULL;
+ KEYDB_SEARCH_DESC desc;
if( opt.batch ) {
log_error(_("sorry, can't do this in batch mode\n"));
return G10ERR_GENERAL;
}
-
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
init_packet( &pkt );
-
- /* search the userid */
- rc = find_secret_keyblock_byname( &kbpos, uname );
- if( rc ) {
- log_error(_("secret key for user `%s' not found\n"), uname );
+ /* search the userid:
+ * We don't want the whole getkey stuff here but the entire keyblock
+ */
+ kdbhd = keydb_new (1);
+ memset (&desc, 0, sizeof desc);
+ desc.mode = classify_user_id (uname,
+ desc.u.kid,
+ desc.u.fpr,
+ &desc.u.name,
+ NULL);
+ rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
+ if (rc) {
+ log_error (_("secret key `%s' not found: %s\n"),
+ uname, g10_errstr (rc));
goto leave;
}
- /* read the keyblock */
- rc = read_keyblock( &kbpos, &keyblock );
+ rc = keydb_get_keyblock (kdbhd, &keyblock );
if( rc ) {
- log_error(_("error reading the certificate: %s\n"), g10_errstr(rc) );
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
goto leave;
}
/* get the keyid from the keyblock */
node = find_kbnode( keyblock, PKT_SECRET_KEY );
- if( !node ) { /* maybe better to use log_bug ? */
- log_error(_("Oops; secret key not found anymore!\n"));
- rc = G10ERR_GENERAL;
- goto leave;
- }
+ if( !node )
+ BUG ();
/* fixme: should make a function out of this stuff,
* it's used all over the source */
@@ -139,6 +144,8 @@ gen_revoke( const char *uname )
tty_printf("\n");
}
pk = m_alloc_clear( sizeof *pk );
+
+ /* FIXME: We should get the public key direct from the secret one */
rc = get_pubkey( pk, sk_keyid );
if( rc ) {
log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
@@ -224,6 +231,7 @@ gen_revoke( const char *uname )
if( sig )
free_seckey_enc( sig );
release_kbnode( keyblock );
+ keydb_release (kdbhd);
if( rc )
iobuf_cancel(out);
else
diff --git a/g10/ringedit.c b/g10/ringedit.c
deleted file mode 100644
index 5e610e583..000000000
--- a/g10/ringedit.c
+++ /dev/null
@@ -1,1796 +0,0 @@
-/* ringedit.c - Function for key ring editing
- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-/****************
- * This module supplies function for:
- *
- * - Search for a key block (pubkey and all other stuff) and return a
- * handle for it.
- *
- * - Lock/Unlock a key block
- *
- * - Read a key block into a tree
- *
- * - Update a key block
- *
- * - Insert a new key block
- *
- * - Delete a key block
- *
- */
-
-
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h> /* for truncate */
-#include <assert.h>
-#ifdef HAVE_LIBGDBM
- #include <gdbm.h>
-#endif
-#include "util.h"
-#include "packet.h"
-#include "memory.h"
-#include "mpi.h"
-#include "iobuf.h"
-#include "keydb.h"
-#include "host2net.h"
-#include "options.h"
-#include "main.h"
-#include "i18n.h"
-
-
-
-
-struct resource_table_struct {
- int used;
- 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;
-
-#define MAX_RESOURCES 10
-static RESTBL resource_table[MAX_RESOURCES];
-static int default_public_resource;
-static int default_secret_resource;
-
-static int search (PKT_public_key *req_pk, u32 *req_keyid,
- KBPOS *kbpos, int secret);
-
-
-static int keyring_search (PKT_public_key *req_pk, u32 *req_keyid,
- 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 );
-
-#ifdef HAVE_LIBGDBM
-static int do_gdbm_store( KBPOS *kbpos, KBNODE root, int update );
-static int do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos,
- const byte *fpr, int fprlen );
-/*static int do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid );*/
-static int do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root );
-static int do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root );
-#endif
-
-
-static RESTBL *
-check_pos( KBPOS *kbpos )
-{
- if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
- return NULL;
- if( !resource_table[kbpos->resno].used )
- return NULL;
- 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
- * 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
-lock_rentry( RESTBL *rentry )
-{
- 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 ****************************
- ****************************************************************/
-
-/****************
- * Get the name of the keyrings, start with a sequence number pointing to a 0.
- */
-const char *
-enum_keyblock_resources( int *sequence, int secret )
-{
- int i = *sequence;
- const char *name = NULL;
-
- for(; i < MAX_RESOURCES; i++ )
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- if( resource_table[i].fname ) {
- name = resource_table[i].fname;
- break;
- }
- }
- *sequence = ++i;
- return name;
-}
-
-
-/****************
- * Register a resource (which currently may only be a keyring file).
- * The first keyring which is added by this function is
- * created if it does not exist.
- * Note: this function may be called before secure memory is
- * available.
- */
-int
-add_keyblock_resource( const char *url, int force, int secret )
-{
- static int any_secret, any_public;
- const char *resname = url;
- IOBUF iobuf = NULL;
- int i;
- char *filename = NULL;
- int rc = 0;
- enum resource_type rt = rt_UNKNOWN;
- const char *created_fname = NULL;
-
- /* Do we have an URL?
- * gnupg-gdbm:filename := this is a GDBM resource
- * gnupg-ring:filename := this is a plain keyring
- * filename := See what is is, but create as plain keyring.
- */
- if( strlen( resname ) > 11 ) {
- if( !strncmp( resname, "gnupg-ring:", 11 ) ) {
- rt = rt_RING;
- resname += 11;
- }
- else if( !strncmp( resname, "gnupg-gdbm:", 11 ) ) {
- rt = rt_GDBM;
- resname += 11;
- }
- #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
- else if( strchr( resname, ':' ) ) {
- log_error("%s: invalid URL\n", url );
- rc = G10ERR_GENERAL;
- goto leave;
- }
- #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
- }
-
- if( *resname != DIRSEP_C ) { /* do tilde expansion etc */
- if( strchr(resname, DIRSEP_C) )
- filename = make_filename(resname, NULL);
- else
- filename = make_filename(opt.homedir, resname, NULL);
- }
- else
- filename = m_strdup( resname );
-
- if( !force )
- force = secret? !any_secret : !any_public;
-
- for(i=0; i < MAX_RESOURCES; i++ )
- if( !resource_table[i].used )
- break;
- if( i == MAX_RESOURCES ) {
- rc = G10ERR_RESOURCE_LIMIT;
- goto leave;
- }
-
- /* see whether we can determine the filetype */
- if( rt == rt_UNKNOWN ) {
- FILE *fp = fopen( filename, "rb" );
-
- if( fp ) {
- u32 magic;
-
- if( fread( &magic, 4, 1, fp) == 1 ) {
- if( magic == 0x13579ace )
- rt = rt_GDBM;
- else if( magic == 0xce9a5713 )
- log_error("%s: endianess does not match\n", url );
- else
- rt = rt_RING;
- }
- else /* maybe empty: assume ring */
- rt = rt_RING;
- fclose( fp );
- }
- else /* no file yet: create ring */
- rt = rt_RING;
- }
-
- switch( rt ) {
- case rt_UNKNOWN:
- log_error("%s: unknown resource type\n", url );
- rc = G10ERR_GENERAL;
- goto leave;
-
- case rt_RING:
- iobuf = iobuf_open( filename );
- if( !iobuf && !force ) {
- rc = G10ERR_OPEN_FILE;
- goto leave;
- }
-
- if( !iobuf ) {
- char *last_slash_in_filename;
-
- last_slash_in_filename = strrchr(filename, DIRSEP_C);
- *last_slash_in_filename = 0;
-
- if( access(filename, F_OK) ) {
- /* on the first time we try to create the default homedir and
- * in this case the process will be terminated, so that on the
- * next invocation it can read the options file in on startup
- */
- try_make_homedir( filename );
- rc = G10ERR_OPEN_FILE;
- *last_slash_in_filename = DIRSEP_C;
- goto leave;
- }
-
- *last_slash_in_filename = DIRSEP_C;
-
- iobuf = iobuf_create( filename );
- if( !iobuf ) {
- log_error(_("%s: can't create keyring: %s\n"),
- filename, strerror(errno));
- rc = G10ERR_OPEN_FILE;
- goto leave;
- }
- else {
- #ifndef HAVE_DOSISH_SYSTEM
- if( secret && !opt.preserve_permissions ) {
- if( chmod( filename, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- filename, strerror(errno) );
- rc = G10ERR_WRITE_FILE;
- goto leave;
- }
- }
- #endif
- if( !opt.quiet )
- log_info(_("%s: keyring created\n"), filename );
- created_fname = filename;
- }
- }
- #if HAVE_DOSISH_SYSTEM || 1
- iobuf_close( iobuf );
- iobuf = NULL;
- if (created_fname) /* must invalidate that ugly cache */
- iobuf_ioctl (NULL, 2, 0, (char*)created_fname);
- #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 = G10ERR_OPEN_FILE;
- goto leave;
- }
- break;
- #endif
-
- default:
- log_error("%s: unsupported resource type\n", url );
- rc = G10ERR_GENERAL;
- goto leave;
- }
-
- #ifndef HAVE_DOSISH_SYSTEM
- #if 0 /* fixme: check directory permissions and print a warning */
- if( secret ) {
- }
- #endif
- #endif
-
- /* fixme: avoid duplicate resources */
- resource_table[i].used = 1;
- resource_table[i].secret = !!secret;
- resource_table[i].fname = m_strdup(filename);
- resource_table[i].iobuf = iobuf;
- resource_table[i].rt = rt;
- if( secret )
- default_secret_resource = i;
- else
- default_public_resource = i;
-
- leave:
- if( rc )
- log_error("keyblock resource `%s': %s\n", filename, g10_errstr(rc) );
- else if( secret )
- any_secret = 1;
- else
- any_public = 1;
- m_free( filename );
- return rc;
-}
-
-/****************
- * Return the resource name of the keyblock associated with KBPOS.
- */
-const char *
-keyblock_resource_name( KBPOS *kbpos )
-{
- RESTBL *rentry;
-
- if( !(rentry = check_pos( kbpos )) || !rentry->fname )
- log_bug("no name for keyblock resource %d\n", kbpos->resno );
- return rentry->fname;
-}
-
-
-/****************
- * Get a keyblock handle KBPOS from a filename. This can be used
- * to get a handle for insert_keyblock for a new keyblock.
- * Using a filename of NULL returns the default resource
- */
-int
-get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos )
-{
- int i = 0;
-
- if( !filename )
- i = secret? default_secret_resource : default_public_resource;
-
- for(; i < MAX_RESOURCES; i++ ) {
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- /* fixme: dos needs case insensitive file compare */
- if( !filename || !strcmp( resource_table[i].fname, filename ) ) {
- memset( kbpos, 0, sizeof *kbpos );
- kbpos->resno = i;
- kbpos->rt = resource_table[i].rt;
- return 0;
- }
- }
- }
- return -1; /* not found */
-}
-
-
-/****************
- * Return the filename of the firstkeyblock resource which is intended
- * for write access. This will either be the default resource or in
- * case this is not writable one of the others. If no writable is found,
- * the default filename in the homedirectory will be returned.
- * Caller must free, will never return NULL.
- */
-char *
-get_writable_keyblock_file( int secret )
-{
- int i = secret? default_secret_resource : default_public_resource;
-
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- if( !access( resource_table[i].fname, R_OK|W_OK ) ) {
- return m_strdup( resource_table[i].fname );
- }
- }
- for(i=0; i < MAX_RESOURCES; i++ ) {
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- if( !access( resource_table[i].fname, R_OK|W_OK ) ) {
- return m_strdup( resource_table[i].fname );
- }
- }
- }
- /* Assume the home dir is always writable */
- return make_filename(opt.homedir, secret? "secring" EXTSEP_S "gpg"
- : "pubring" EXTSEP_S "gpg", NULL );
-}
-
-
-/****************
- * 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 (PKT_public_key *req_pk, u32 *req_keyid, KBPOS *kbpos, int secret)
-{
- 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 (req_pk, req_keyid,
- kbpos, resource_table[i].iobuf,
- resource_table[i].fname );
-
- break;
- #ifdef HAVE_LIBGDBM
- case rt_GDBM: {
- byte fpr[20];
- size_t fprlen;
-
- if (!req_pk)
- rc = G10ERR_UNSUPPORTED;
- else {
- 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, g10_errstr(rc));
- last_rc = rc;
- }
- }
- }
- return last_rc;
-}
-
-
-/****************
- * Combined function to search for a username and get the position
- * of the keyblock.
- */
-int
-find_keyblock_byname( KBPOS *kbpos, const char *username )
-{
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
- int rc;
-
- rc = get_pubkey_byname( NULL, pk, username, NULL );
- if (!rc)
- rc = search( pk, NULL, 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 )
-{
- int rc;
-
- rc = search( pk, NULL, kbpos, 0 );
- return rc;
-}
-
-/****************
- * Combined function to search for a secret key and get the position
- * of the keyblock.
- */
-int
-find_secret_keyblock_bypk (KBPOS *kbpos, PKT_public_key *pk)
-{
- int rc;
-
- rc = search (pk, NULL, kbpos, 1);
- 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 )
-{
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
- int rc;
-
- rc = get_pubkey_byname( NULL, pk, username, NULL );
- if (!rc)
- rc = search (pk, NULL, kbpos, 1);
- free_public_key (pk);
- return rc;
-}
-
-/*
- * This function locates the secret keyblock without doing a public
- * keyring check fist. It is useful in certain situations and much
- * faster than the generic solution.
- */
-int
-find_secret_keyblock_direct (KBPOS *kbpos, u32 *keyid)
-{
- int rc;
- rc = search (NULL, keyid, kbpos, 1);
- return 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 )
-{
- if( !check_pos(kbpos) )
- return G10ERR_GENERAL;
- return 0;
-}
-
-/****************
- * Release a lock on a keyblock
- */
-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 G10ERR_GENERAL;
-
- switch( kbpos->rt ) {
- case rt_RING:
- return keyring_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.
- * Mode is: 0 = open
- * 1 = read
- * 2 = close
- * 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 )
-{
- int rc = 0;
- RESTBL *rentry;
-
- if( !mode || mode == 5 || mode == 100 ) {
- int i;
-
- kbpos->fp = NULL;
- kbpos->rt = rt_UNKNOWN;
- if( !mode ) {
- kbpos->secret = 0;
- i = 0;
- }
- else if( mode == 5 ) {
- kbpos->secret = 1;
- mode = 0;
- i = 0;
- }
- else
- i = kbpos->resno+1;
- for(; i < MAX_RESOURCES; i++ )
- if( resource_table[i].used
- && !resource_table[i].secret == !kbpos->secret )
- break;
- if( i == MAX_RESOURCES )
- return -1; /* no resources */
- kbpos->resno = i;
- rentry = check_pos( kbpos );
- kbpos->rt = resource_table[i].rt;
- kbpos->valid = 0;
- switch( kbpos->rt ) {
- case rt_RING:
- kbpos->fp = iobuf_open( rentry->fname );
- if( !kbpos->fp ) {
- log_error("can't open `%s'\n", rentry->fname );
- return G10ERR_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;
- }
- else if( mode == 1 || mode == 11 ) {
- int cont;
- do {
- cont = 0;
- switch( kbpos->rt ) {
- case rt_RING:
- if( !kbpos->fp )
- return G10ERR_GENERAL;
- rc = keyring_enum( kbpos, ret_root, mode == 11 );
- break;
- #ifdef HAVE_LIBGDBM
- case rt_GDBM:
- rc = do_gdbm_enum( kbpos, ret_root );
- break;
- #endif
- default: BUG();
- }
-
- if( rc == -1 ) {
- assert( !kbpos->pkt );
- rentry = check_pos( kbpos );
- assert(rentry);
- /* close */
- enum_keyblocks(2, kbpos, ret_root );
- /* and open the next one */
- rc = enum_keyblocks(100, kbpos, ret_root );
- if( !rc )
- cont = 1;
- }
- } while(cont);
- }
- else {
- switch( kbpos->rt ) {
- case rt_RING:
- if( kbpos->fp ) {
- iobuf_close( kbpos->fp );
- kbpos->fp = NULL;
- }
- break;
- case rt_GDBM:
- break;
- case rt_UNKNOWN:
- /* this happens when we have no keyring at all */
- return rc;
-
- default:
- BUG();
- }
- /* release pending packet */
- free_packet( kbpos->pkt );
- m_free( kbpos->pkt );
- }
- return rc;
-}
-
-
-
-
-/****************
- * Insert the keyblock described by ROOT into the keyring described
- * by KBPOS. This actually appends the data to the keyfile.
- */
-int
-insert_keyblock( KBPOS *kbpos, KBNODE root )
-{
- int rc;
-
- if( !check_pos(kbpos) )
- return G10ERR_GENERAL;
-
- switch( kbpos->rt ) {
- case rt_RING:
- rc = keyring_copy( kbpos, 1, root );
- break;
- #ifdef HAVE_LIBGDBM
- case rt_GDBM:
- rc = do_gdbm_store( kbpos, root, 0 );
- break;
- #endif
- default: BUG();
- }
-
- return rc;
-}
-
-/****************
- * Delete the keyblock described by KBPOS.
- * The current code simply changes the keyblock in the keyring
- * to packet of type 0 with the correct length. To help detect errors,
- * zero bytes are written.
- */
-int
-delete_keyblock( KBPOS *kbpos )
-{
- int rc;
-
- if( !check_pos(kbpos) )
- return G10ERR_GENERAL;
-
- switch( kbpos->rt ) {
- case rt_RING:
- rc = keyring_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();
- }
-
- return rc;
-}
-
-
-/****************
- * Update the keyblock at KBPOS with the one in ROOT.
- */
-int
-update_keyblock( KBPOS *kbpos, KBNODE root )
-{
- int rc;
-
- if( !check_pos(kbpos) )
- return G10ERR_GENERAL;
-
- switch( kbpos->rt ) {
- case rt_RING:
- rc = keyring_copy( kbpos, 3, root );
- break;
- #ifdef HAVE_LIBGDBM
- case rt_GDBM:
- rc = do_gdbm_store( kbpos, root, 1 );
- break;
- #endif
- default: BUG();
- }
-
- return rc;
-}
-
-
-
-/****************************************************************
- ********** 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 = m_alloc_clear( 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=ascii_toupper(buf[k]); c == pat[j];
- j--, k--, c=ascii_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 = m_alloc_clear( 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 )
-{
- m_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_public_key *req_pk, PKT_secret_key *sk )
-{
- int n,i;
-
- if (req_pk->pubkey_algo != sk->pubkey_algo)
- return -1;
-
- n = pubkey_get_npkey (req_pk->pubkey_algo);
- for (i=0; i < n; i++ ) {
- if( mpi_cmp (req_pk->pkey[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( PKT_public_key *req_pk, u32 *req_keyid,
- KBPOS *kbpos, IOBUF iobuf, const char *fname )
-{
- int rc;
- PACKET pkt;
- int save_mode;
- off_t offset, main_offset;
-
- assert (!!req_pk ^ !!req_keyid); /* exactly one must be specified */
- 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 = G10ERR_KEYRING_OPEN;
- goto leave;
- }
- #else
- if( iobuf_seek( iobuf, 0 ) ) {
- log_error("can't rewind keyring file\n");
- rc = G10ERR_KEYRING_OPEN;
- goto leave;
- }
- #endif
-
- main_offset = 0;
- while ( !(rc=search_packet(iobuf, &pkt, &offset)) ) {
- if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY) {
- main_offset = offset;
- }
-
- if (pkt.pkttype == PKT_SECRET_KEY || pkt.pkttype == PKT_SECRET_SUBKEY) {
- PKT_secret_key *sk = pkt.pkt.secret_key;
-
- if (req_keyid) {
- u32 aki[2];
-
- keyid_from_sk (sk, aki);
- if (aki[0] == req_keyid[0] && aki[1] == req_keyid[1])
- break; /* found */
- }
- else {
- /* We can't compare the timestamps here because they
- might differ */
- if( !cmp_seckey (req_pk, sk) )
- break; /* found */
- }
- }
- else if (pkt.pkttype == PKT_PUBLIC_KEY
- || pkt.pkttype == PKT_PUBLIC_SUBKEY) {
- PKT_public_key *pk = pkt.pkt.public_key;
-
- if (req_keyid) {
- u32 aki[2];
-
- keyid_from_pk (pk, aki);
- if (aki[0] == req_keyid[0] && aki[1] == req_keyid[1])
- break; /* found */
- }
- else {
- 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 ) {
- if (pkt.pkttype == PKT_SECRET_SUBKEY
- || pkt.pkttype == PKT_PUBLIC_SUBKEY)
- kbpos->offset = main_offset;
- else
- 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 G10ERR_GENERAL;
-
- a = iobuf_open( rentry->fname );
- if( !a ) {
- log_error("can't open `%s'\n", rentry->fname );
- return G10ERR_OPEN_FILE;
- }
-
- if( !kbpos->valid )
- log_debug("kbpos not valid in keyring_read\n" );
- if( iobuf_seek( a, kbpos->offset ) ) {
- log_error("can't seek\n");
- iobuf_close(a);
- return G10ERR_KEYRING_OPEN;
- }
-
- pkt = m_alloc( sizeof *pkt );
- init_packet(pkt);
- kbpos->count=0;
- while( (rc=parse_packet(a, pkt)) != -1 ) {
- if( rc ) { /* ignore errors */
- if( rc != G10ERR_UNKNOWN_PACKET ) {
- log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
- rc = G10ERR_INV_KEYRING;
- goto ready;
- }
- 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 = m_alloc( 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 );
- m_free( pkt );
- iobuf_close(a);
- return rc;
-}
-
-
-static int
-keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
-{
- PACKET *pkt;
- int rc;
- RESTBL *rentry;
- KBNODE root = NULL;
-
- if( !(rentry=check_pos(kbpos)) )
- return G10ERR_GENERAL;
-
- if( kbpos->pkt ) {
- root = new_kbnode( kbpos->pkt );
- kbpos->pkt = NULL;
- }
-
- pkt = m_alloc( sizeof *pkt );
- init_packet(pkt);
- while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
- if( rc ) { /* ignore errors */
- if( rc != G10ERR_UNKNOWN_PACKET ) {
- log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
- rc = G10ERR_INV_KEYRING;
- goto ready;
- }
- free_packet( pkt );
- init_packet( pkt );
- continue;
- }
- /* make a linked list of all packets */
- switch( pkt->pkttype ) {
- case PKT_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( root ) { /* store this packet */
- kbpos->pkt = pkt;
- pkt = NULL;
- goto ready;
- }
- root = new_kbnode( pkt );
- pkt = m_alloc( sizeof *pkt );
- init_packet(pkt);
- break;
-
- default:
- /* skip pakets at the beginning of a keyring, until we find
- * a start packet; issue a warning if it is not a comment */
- if( !root && pkt->pkttype != PKT_COMMENT
- && pkt->pkttype != PKT_OLD_COMMENT ) {
- break;
- }
- if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
- ||pkt->pkttype == PKT_COMMENT
- ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
- init_packet(pkt);
- break;
- }
- add_kbnode( root, new_kbnode( pkt ) );
- pkt = m_alloc( sizeof *pkt );
- init_packet(pkt);
- break;
- }
- }
- ready:
- if( rc == -1 && root )
- rc = 0;
-
- if( rc )
- release_kbnode( root );
- else
- *ret_root = root;
- free_packet( pkt );
- m_free( pkt );
-
- return rc;
-}
-
-
-/****************
- * Perform insert/delete/update operation.
- * mode 1 = insert
- * 2 = delete
- * 3 = update
- */
-static int
-keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
-{
- RESTBL *rentry;
- IOBUF fp, newfp;
- int rc=0;
- char *bakfname = NULL;
- char *tmpfname = NULL;
-
- if( !(rentry = check_pos( kbpos )) )
- return G10ERR_GENERAL;
- if( kbpos->fp )
- BUG(); /* not allowed with such a handle */
-
- if( opt.dry_run )
- return 0;
-
- lock_rentry( rentry );
-
- /* open the source file */
- fp = iobuf_open( rentry->fname );
- if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
- KBNODE kbctx, node;
-
- /* insert: create a new file */
- newfp = iobuf_create( rentry->fname );
- if( !newfp ) {
- log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
- unlock_rentry( rentry );
- return G10ERR_OPEN_FILE;
- }
- else if( !opt.quiet )
- log_info(_("%s: keyring created\n"), rentry->fname );
-
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( (rc = build_packet( newfp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, g10_errstr(rc) );
- iobuf_cancel(newfp);
- unlock_rentry( rentry );
- return G10ERR_WRITE_FILE;
- }
- }
- if( iobuf_close(newfp) ) {
- log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
- 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) );
- unlock_rentry( rentry );
- return G10ERR_WRITE_FILE;
- }
- return 0;
- }
- if( !fp ) {
- log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
- rc = G10ERR_OPEN_FILE;
- goto leave;
- }
-
- /* create the new file */
- #ifdef USE_ONLY_8DOT3
- /* Here is another Windoze bug?:
- * you cant rename("pubring.gpg.tmp", "pubring.gpg");
- * but rename("pubring.gpg.tmp", "pubring.aaa");
- * works. So we replace .gpg by .bak or .tmp
- */
- if( strlen(rentry->fname) > 4
- && !strcmp(rentry->fname+strlen(rentry->fname)-4, EXTSEP_S "gpg") ) {
- bakfname = m_alloc( strlen( rentry->fname ) + 1 );
- strcpy(bakfname,rentry->fname);
- strcpy(bakfname+strlen(rentry->fname)-4, EXTSEP_S "bak");
- tmpfname = m_alloc( strlen( rentry->fname ) + 1 );
- strcpy(tmpfname,rentry->fname);
- strcpy(tmpfname+strlen(rentry->fname)-4, EXTSEP_S "tmp");
- }
- else { /* file does not end with gpg; hmmm */
- bakfname = m_alloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(bakfname,rentry->fname), EXTSEP_S "bak");
- tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(tmpfname,rentry->fname), EXTSEP_S "tmp");
- }
- #else
- bakfname = m_alloc( strlen( rentry->fname ) + 2 );
- strcpy(stpcpy(bakfname,rentry->fname),"~");
- tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(tmpfname,rentry->fname), EXTSEP_S "tmp");
- #endif
- newfp = iobuf_create( tmpfname );
- if( !newfp ) {
- log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
- iobuf_close(fp);
- rc = G10ERR_OPEN_FILE;
- goto leave;
- }
-
- if( mode == 1 ) { /* insert */
- /* copy everything to the new file */
- rc = copy_all_packets( fp, newfp );
- if( rc != -1 ) {
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, g10_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- rc = 0;
- }
-
- if( mode == 2 || mode == 3 ) { /* delete or update */
- /* copy first part to the new file */
- rc = copy_some_packets( fp, newfp, kbpos->offset );
- if( rc ) { /* should never get EOF here */
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, g10_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- /* skip this keyblock */
- assert( kbpos->count );
- rc = skip_some_packets( fp, kbpos->count );
- if( rc ) {
- log_error("%s: skipping %u packets failed: %s\n",
- rentry->fname, kbpos->count, g10_errstr(rc));
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- }
-
- if( mode == 1 || mode == 3 ) { /* insert or update */
- KBNODE kbctx, node;
-
- /* append the new data */
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( (rc = build_packet( newfp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, g10_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- rc = G10ERR_WRITE_FILE;
- goto leave;
- }
- }
- kbpos->valid = 0;
- }
-
- if( mode == 2 || mode == 3 ) { /* delete or update */
- /* copy the rest */
- rc = copy_all_packets( fp, newfp );
- if( rc != -1 ) {
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, g10_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- rc = 0;
- }
-
- /* close both files */
- if( iobuf_close(fp) ) {
- log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
- rc = G10ERR_CLOSE_FILE;
- goto leave;
- }
- if( iobuf_close(newfp) ) {
- log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
- rc = G10ERR_CLOSE_FILE;
- goto leave;
- }
- /* if the new file is a secring, restrict the permissions */
- #ifndef HAVE_DOSISH_SYSTEM
- if( rentry->secret && !opt.preserve_permissions ) {
- if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- tmpfname, strerror(errno) );
- rc = G10ERR_WRITE_FILE;
- goto leave;
- }
- }
- #endif
-
- /* rename and make backup file */
- if( !rentry->secret ) { /* but not for secret keyrings */
- iobuf_ioctl (NULL, 2, 0, bakfname );
- iobuf_ioctl (NULL, 2, 0, rentry->fname );
- #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
- remove( bakfname );
- #endif
- if( rename( rentry->fname, bakfname ) ) {
- log_error("%s: rename to %s failed: %s\n",
- rentry->fname, bakfname, strerror(errno) );
- rc = G10ERR_RENAME_FILE;
- goto leave;
- }
- }
- iobuf_ioctl (NULL, 2, 0, tmpfname );
- iobuf_ioctl (NULL, 2, 0, rentry->fname );
- #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
- remove( rentry->fname );
- #endif
- if( rename( tmpfname, rentry->fname ) ) {
- log_error("%s: rename to %s failed: %s\n",
- tmpfname, rentry->fname,strerror(errno) );
- rc = G10ERR_RENAME_FILE;
- if( rentry->secret ) {
- log_info(_(
- "WARNING: 2 files with confidential information exists.\n"));
- log_info(_("%s is the unchanged one\n"), rentry->fname );
- log_info(_("%s is the new one\n"), tmpfname );
- log_info(_("Please fix this possible security flaw\n"));
- }
- goto leave;
- }
-
- leave:
- unlock_rentry( rentry );
- m_free(bakfname);
- m_free(tmpfname);
- return rc;
-}
-
-
-#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 G10ERR_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, g10_errstr(rc) );
- rc = G10ERR_WRITE_FILE;
- goto leave;
- }
- }
- /* store data and key */
- *keybuf = 1; /* key is a padded fingerprint */
- memcpy(keybuf+1, fpr, 20 );
- key.dptr = keybuf;
- key.dsize = 21;
- content.dptr = iobuf_get_temp_buffer( fp );
- content.dsize = iobuf_get_temp_length( fp );
- rc = gdbm_store( rentry->dbf, key, content,
- update? GDBM_REPLACE : GDBM_INSERT );
- if( rc == 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 = G10ERR_WRITE_FILE;
- goto leave;
- }
- /* now store all keyids */
- *contbuf = 2; /* data is a list of fingerprints */
- memcpy(contbuf+1, fpr, 20 );
- content.dptr = contbuf;
- content.dsize= 21;
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( node->pkt->pkttype == PKT_PUBLIC_KEY
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- u32 aki[2];
-
- keyid_from_pk( node->pkt->pkt.public_key, aki );
- *keybuf = 2; /* key is a 8 byte keyid */
- u32tobuf( keybuf+1 , aki[0] );
- u32tobuf( keybuf+5, aki[1] );
- key.dptr = keybuf;
- key.dsize= 9;
- /* fixme: must be more clever when a insert failed:
- * build a list of fingerprints in this case */
- rc = gdbm_store( rentry->dbf, key, content,
- update? GDBM_REPLACE : GDBM_INSERT );
- if( rc ) {
- log_info("%s: gdbm_store keyid failed: %s\n", rentry->fname,
- rc == 1 ? "already stored"
- : gdbm_strerror(gdbm_errno) );
- rc = 0;
- }
- }
- }
-
- leave:
- iobuf_close(fp); /* don't need a cancel because it is a temp iobuf */
- return rc;
-}
-
-
-
-/****************
- * search one keybox, return 0 if found, -1 if not found or an errorcode.
- */
-static int
-do_gdbm_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
- */
-#if 0 /* not used */
-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 m_free() here */
- return G10ERR_INV_KEYRING;
- }
- if( *content.dptr != 2 ) {
- log_error("gdbm_fetch returned unexpected type %d\n",
- *(byte*)content.dptr );
- free( content.dptr ); /* can't use m_free() here */
- return G10ERR_INV_KEYRING;
- }
- if( content.dsize < 21 ) {
- log_error("gdbm_fetch did not return a complete fingerprint\n" );
- free( content.dptr ); /* can't use m_free() here */
- return G10ERR_INV_KEYRING;
- }
- if( content.dsize > 21 )
- log_info("gdbm_fetch: WARNING: more than one fingerprint\n" );
-
- rc = do_gdbm_locate( dbf, kbpos, content.dptr+1, 20 );
- free( content.dptr ); /* can't use m_free() here */
- return rc;
-}
-#endif /* not used */
-
-
-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 G10ERR_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 G10ERR_INV_KEYRING;
- }
- if( content.dsize < 2 ) {
- log_error("gdbm_fetch did not return enough data\n" );
- free( content.dptr ); /* can't use m_free() here */
- return G10ERR_INV_KEYRING;
- }
- if( *content.dptr != 1 ) {
- log_error("gdbm_fetch returned unexpected type %d\n",
- *(byte*)content.dptr );
- free( content.dptr ); /* can't use m_free() here */
- return G10ERR_INV_KEYRING;
- }
-
- a = iobuf_temp_with_content( content.dptr+1, content.dsize-1 );
- free( content.dptr ); /* can't use m_free() here */
-
- pkt = m_alloc( sizeof *pkt );
- init_packet(pkt);
- kbpos->count=0;
- while( (rc=parse_packet(a, pkt)) != -1 ) {
- if( rc ) { /* ignore errors */
- if( rc != G10ERR_UNKNOWN_PACKET ) {
- log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
- rc = G10ERR_INV_KEYRING;
- 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 = m_alloc( sizeof *pkt );
- init_packet(pkt);
- }
- if( rc == -1 && root )
- rc = 0;
- if( rc )
- release_kbnode( root );
- else
- *ret_root = root;
- free_packet( pkt );
- m_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 G10ERR_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 m_free() ! */
- }
- if( !key.dptr )
- return -1; /* eof */
-
- if( key.dsize < 21 ) {
- free( key.dptr ); /* free and not m_free() ! */
- log_error("do_gdm_enum: key is too short\n" );
- return G10ERR_INV_KEYRING;
- }
- memcpy( kbpos->keybuf, key.dptr, 21 );
- free( key.dptr ); /* free and not m_free() ! */
- return do_gdbm_read( kbpos, ret_root );
-}
-
-#endif /*HAVE_LIBGDBM*/
diff --git a/g10/status.c b/g10/status.c
index 9ada277da..7a7ddf850 100644
--- a/g10/status.c
+++ b/g10/status.c
@@ -140,6 +140,7 @@ get_status_string ( int no )
case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
case STATUS_USERID_HINT : s = "USERID_HINT"; break;
case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
+ case STATUS_INV_RECP : s = "INV_RECP"; break;
default: s = "?"; break;
}
return s;
diff --git a/g10/status.h b/g10/status.h
index 271959fa6..840df62ec 100644
--- a/g10/status.h
+++ b/g10/status.h
@@ -90,6 +90,8 @@
#define STATUS_KEY_CREATED 58
#define STATUS_USERID_HINT 59
#define STATUS_UNEXPECTED 60
+#define STATUS_INV_RECP 61
+
/*-- status.c --*/
void set_status_fd ( int fd );
diff --git a/g10/tdbdump.c b/g10/tdbdump.c
index d1a6b3120..b44cdbd95 100644
--- a/g10/tdbdump.c
+++ b/g10/tdbdump.c
@@ -352,7 +352,7 @@ list_trustdb( const char *username )
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc;
- if( (rc = get_pubkey_byname( NULL, pk, username, NULL )) )
+ if( (rc = get_pubkey_byname( pk, username, NULL, NULL )) )
log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
log_error(_("problem finding '%s' in trustdb: %s\n"),
diff --git a/g10/trustdb.c b/g10/trustdb.c
index b7e5bbd6c..9de778aa4 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -1697,22 +1697,28 @@ void
update_trustdb()
{
KBNODE keyblock = NULL;
- KBPOS kbpos;
+ KEYDB_HANDLE kdbhd;
int rc;
if( opt.dry_run )
return;
init_trustdb();
- rc = enum_keyblocks( 0, &kbpos, &keyblock );
- if( !rc ) {
+ kdbhd = keydb_new (0);
+ rc = keydb_search_first (kdbhd);
+ if (!rc) {
ulong count=0, err_count=0, new_count=0;
- while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
- /*int modified;*/
+ do {
TRUSTREC drec;
- PKT_public_key *pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key;
+ PKT_public_key *pk;
+ /*int modified;*/
+
+ rc = keydb_get_keyblock (kdbhd, &keyblock );
+ if (rc)
+ break;
+
+ pk = find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt.public_key;
rc = get_dir_record( pk, &drec );
if( rc == -1 ) { /* not in trustdb: insert */
@@ -1741,7 +1747,7 @@ update_trustdb()
release_kbnode( keyblock ); keyblock = NULL;
if( !(++count % 100) )
log_info(_("%lu keys so far processed\n"), count);
- }
+ } while ( !(rc = keydb_search_next (kdbhd)));
log_info(_("%lu keys processed\n"), count);
if( err_count )
log_info(_("\t%lu keys with errors\n"), err_count);
@@ -1751,7 +1757,7 @@ update_trustdb()
if( rc && rc != -1 )
log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
- enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+ keydb_release (kdbhd);
release_kbnode( keyblock );
}
@@ -2514,7 +2520,7 @@ list_trust_path( const char *username )
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
init_trustdb();
- if( (rc = get_pubkey_byname(NULL, pk, username, NULL )) )
+ if( (rc = get_pubkey_byname (pk, username, NULL, NULL )) )
log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
log_error(_("problem finding '%s' in trustdb: %s\n"),
diff --git a/scripts/autogen.sh b/scripts/autogen.sh
index ac4bc2dae..46744cd2e 100755
--- a/scripts/autogen.sh
+++ b/scripts/autogen.sh
@@ -120,7 +120,7 @@ if (gettext --version </dev/null 2>/dev/null | awk 'NR==1 { split($4,A,"\."); \
X=10000*A[1]+100*A[2]+A[3]; echo X; if( X >= 1038 ) exit 1; exit 0}')
then
echo "**Error**: You must have "\`gettext\'" installed to compile $PGM."
- echo ' (version 0.10.35 or newer is required; get'
+ echo ' (version 0.10.38 or newer is required; get'
echo ' ftp://alpha.gnu.org/gnu/gettext/gettext-0.10.38.tar.gz'
echo ' or install the latest Debian package)'
DIE="yes"
diff --git a/tools/gpgsplit.c b/tools/gpgsplit.c
index 3094550f1..707f17147 100644
--- a/tools/gpgsplit.c
+++ b/tools/gpgsplit.c
@@ -49,7 +49,6 @@ enum cmd_and_opt_values { aNull = 0,
oPrefix = 'p',
aTest };
-#warning Add an option to split a keyring into reasonable sized chunks.
static ARGPARSE_OPTS opts[] = {
diff --git a/util/ChangeLog b/util/ChangeLog
index 77ffb4f30..ccbe1764b 100644
--- a/util/ChangeLog
+++ b/util/ChangeLog
@@ -1,3 +1,7 @@
+2001-09-03 Werner Koch <[email protected]>
+
+ * miscutil.c (strtimestamp,asctimestamp): Avoid trigraphs.
+
2001-08-21 Stefan Bellon <[email protected]>
* riscos.c [__riscos__] (close_fds): Fixed possible endless loop.
diff --git a/util/miscutil.c b/util/miscutil.c
index dbe6db4ff..928ec3bc7 100644
--- a/util/miscutil.c
+++ b/util/miscutil.c
@@ -126,7 +126,7 @@ strtimestamp( u32 stamp )
time_t atime = stamp;
if (atime < 0) {
- strcpy (buffer, "????-??-??");
+ strcpy (buffer, "????" "-??" "-??");
}
else {
tp = gmtime( &atime );
@@ -150,7 +150,7 @@ asctimestamp( u32 stamp )
time_t atime = stamp;
if (atime < 0) {
- strcpy (buffer, "????-??-??");
+ strcpy (buffer, "????" "-??" "-??");
return buffer;
}