From 4c76d6dce1113750f220e9730b83efc7329668bb Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 28 May 2001 17:35:10 +0000 Subject: [PATCH] Changes by Jose and Tommy. --- gpgme/ChangeLog | 25 +++++- gpgme/decrypt.c | 4 +- gpgme/encrypt.c | 1 - gpgme/key.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++- gpgme/key.h | 5 ++ gpgme/keylist.c | 6 +- gpgme/rungpg.c | 1 - gpgme/verify.c | 26 ++++--- gpgme/version.c | 7 +- tests/t-verify.c | 4 +- 10 files changed, 250 insertions(+), 24 deletions(-) diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 017ab28b..a8242e5b 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,26 @@ +2001-05-28 Werner Koch + + * version.c (gpgme_check_engine): Stop version number parsing at + the opening angle and not the closing one. By Tommy Reynolds. + +2001-05-01 José Carlos García Sogo + + * encrypt.c (gpgme_op_encrypt_start): Deleted the assert ( !c->gpg ) + line, because it gave an error if another operation had been made + before using the same context. + + * decrypt.c (gpgme_op_decrypt_start): The same as above. Also added + one line to release the gpg object in the context (if any). + +2001-04-26 Werner Koch + + * key.c, key.h (_gpgme_key_cache_init): New. + (_gpgme_key_cache_add): New. + (_gpgme_key_cache_get): New. + * version.c (do_subsystem_inits): Init the cache. + * keylist.c (finish_key): Put key into the cache + * verify.c (gpgme_get_sig_key): First look into the cache. + 2001-04-19 Werner Koch * keylist.c (parse_timestamp): Adjusted for the changed @@ -208,4 +231,4 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, to the extent permitted by law; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - \ No newline at end of file + diff --git a/gpgme/decrypt.c b/gpgme/decrypt.c index 526a8156..5982301b 100644 --- a/gpgme/decrypt.c +++ b/gpgme/decrypt.c @@ -195,9 +195,9 @@ gpgme_op_decrypt_start ( GpgmeCtx c, c->out_of_core = 0; /* do some checks */ - assert ( !c->gpg ); - + /* create a process object */ + _gpgme_gpg_release ( c->gpg ); rc = _gpgme_gpg_new ( &c->gpg ); if (rc) goto leave; diff --git a/gpgme/encrypt.c b/gpgme/encrypt.c index 5234cc8b..3fe60a62 100644 --- a/gpgme/encrypt.c +++ b/gpgme/encrypt.c @@ -49,7 +49,6 @@ gpgme_op_encrypt_start ( GpgmeCtx c, GpgmeRecipients recp, c->pending = 1; /* do some checks */ - assert ( !c->gpg ); if ( !gpgme_recipients_count ( recp ) ) { /* Fixme: In this case we should do symmentric encryption */ rc = mk_error (No_Recipients); diff --git a/gpgme/key.c b/gpgme/key.c index f61d2c1c..966675e3 100644 --- a/gpgme/key.c +++ b/gpgme/key.c @@ -31,6 +31,199 @@ #define ALLOC_CHUNK 1024 #define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) +#if SIZEOF_UNSIGNED_INT < 4 +#error unsigned int too short to be used as a hash value +#endif + +struct key_cache_item_s { + struct key_cache_item_s *next; + GpgmeKey key; +}; + +static int key_cache_initialized; +static struct key_cache_item_s **key_cache; +static size_t key_cache_size; +static size_t key_cache_max_chain_length; +static struct key_cache_item_s *key_cache_unused_items; + +static int +hextobyte ( const byte *s ) +{ + int c; + + if ( *s >= '0' && *s <= '9' ) + c = 16 * (*s - '0'); + else if ( *s >= 'A' && *s <= 'F' ) + c = 16 * (10 + *s - 'A'); + else if ( *s >= 'a' && *s <= 'f' ) + c = 16 * (10 + *s - 'a'); + else + return -1; + s++; + if ( *s >= '0' && *s <= '9' ) + c += *s - '0'; + else if ( *s >= 'A' && *s <= 'F' ) + c += 10 + *s - 'A'; + else if ( *s >= 'a' && *s <= 'f' ) + c += 10 + *s - 'a'; + else + return -1; + return c; +} + +static int +hash_key (const char *fpr, unsigned int *rhash) +{ + unsigned int hash; + int c; + + if ( !fpr ) return -1; + if ( (c = hextobyte(fpr)) == -1 ) return -1; + hash = c; + if ( (c = hextobyte(fpr+2)) == -1 ) return -1; + hash |= c << 8; + if ( (c = hextobyte(fpr+4)) == -1 ) return -1; + hash |= c << 16; + if ( (c = hextobyte(fpr+6)) == -1 ) return -1; + hash |= c << 24; + + *rhash = hash; + return 0; +} + +void +_gpgme_key_cache_init (void) +{ + if (key_cache_initialized) + return; + key_cache_size = 503; + key_cache = xtrycalloc (key_cache_size, sizeof *key_cache); + if (!key_cache) { + key_cache_size = 0; + key_cache_initialized = 1; + return; + } + /* + * The upper bound for our cache size is + * key_cache_max_chain_length * key_cache_size + */ + key_cache_max_chain_length = 10; + key_cache_initialized = 1; +} + + +void +_gpgme_key_cache_add (GpgmeKey key) +{ + struct subkey_s *k; +#warning debug code + if (!key || getenv("gpgme_no_cache") ) + return; + + /* FIXME: add locking */ + if (!key_cache_initialized) + _gpgme_key_cache_init (); + if (!key_cache_size) + return; /* cache was not enabled */ + + /* put the key under each fingerprint into the cache. We use the + * first 4 digits to calculate the hash */ + for (k=&key->keys; k; k = k->next ) { + size_t n; + unsigned int hash; + struct key_cache_item_s *item; + + if ( hash_key (k->fingerprint, &hash) ) + continue; + + hash %= key_cache_size; + for (item=key_cache[hash],n=0; item; item = item->next, n++) { + struct subkey_s *k2; + if (item->key == key) + break; /* already in cache */ + /* now do a deeper check */ + for (k2=&item->key->keys; k2; k2 = k2->next ) { + if( k2->fingerprint + && !strcmp (k->fingerprint, k2->fingerprint) ) { + /* okay, replace it with the new copy */ + gpgme_key_unref (item->key); + item->key = key; + gpgme_key_ref (item->key); + return; + } + } + } + if (item) + continue; + + if (n > key_cache_max_chain_length ) { /* remove the last entries */ + struct key_cache_item_s *last = NULL; + + for (item=key_cache[hash]; + item && n < key_cache_max_chain_length; + last = item, item = item->next, n++ ) { + ; + } + if (last) { + struct key_cache_item_s *next; + + assert (last->next == item); + last->next = NULL; + for ( ;item; item=next) { + next = item->next; + gpgme_key_unref (item->key); + item->key = NULL; + item->next = key_cache_unused_items; + key_cache_unused_items = item; + } + } + } + + item = key_cache_unused_items; + if (item) { + key_cache_unused_items = item->next; + item->next = NULL; + } + else { + item = xtrymalloc (sizeof *item); + if (!item) + return; /* out of core */ + } + + item->key = key; + gpgme_key_ref (key); + item->next = key_cache[hash]; + key_cache[hash] = item; + } +} + + +GpgmeKey +_gpgme_key_cache_get (const char *fpr) +{ + struct key_cache_item_s *item; + unsigned int hash; + + if (!key_cache_size) + return NULL; /* cache not (yet) enabled */ + + if (hash_key (fpr, &hash)) + return NULL; + + hash %= key_cache_size; + for (item=key_cache[hash]; item; item = item->next) { + struct subkey_s *k; + + for (k=&item->key->keys; k; k = k->next ) { + if( k->fingerprint && !strcmp (k->fingerprint, fpr) ) { + gpgme_key_ref (item->key); + return item->key; + } + } + } + return NULL; +} + static const char * pkalgo_to_string ( int algo ) @@ -47,8 +240,6 @@ pkalgo_to_string ( int algo ) } - - static GpgmeError key_new ( GpgmeKey *r_key, int secret ) { diff --git a/gpgme/key.h b/gpgme/key.h index 60244e97..003821a5 100644 --- a/gpgme/key.h +++ b/gpgme/key.h @@ -61,6 +61,11 @@ struct gpgme_key_s { struct user_id_s *uids; }; +void _gpgme_key_cache_init (void); +void _gpgme_key_cache_add (GpgmeKey key); +GpgmeKey _gpgme_key_cache_get (const char *fpr); + + struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key); struct subkey_s *_gpgme_key_add_secret_subkey (GpgmeKey key); GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); diff --git a/gpgme/keylist.c b/gpgme/keylist.c index 9d7824bb..11e10cf2 100644 --- a/gpgme/keylist.c +++ b/gpgme/keylist.c @@ -341,10 +341,12 @@ finish_key ( GpgmeCtx ctx ) { GpgmeKey key = ctx->tmp_key; struct key_queue_item_s *q, *q2; - + assert (key); ctx->tmp_key = NULL; - + + _gpgme_key_cache_add (key); + q = xtrymalloc ( sizeof *q ); if ( !q ) { gpgme_key_release (key); diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 6f731e51..708b2781 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -1094,7 +1094,6 @@ read_status ( GpgObject gpg ) if ( *p == '\n' ) { /* (we require that the last line is terminated by a LF) */ *p = 0; - fflush (stdout); fprintf (stderr, "read_status: `%s'\n", buffer); if (!strncmp (buffer, "[GNUPG:] ", 9 ) && buffer[9] >= 'A' && buffer[9] <= 'Z' ) { struct status_table_s t, *r; diff --git a/gpgme/verify.c b/gpgme/verify.c index 0d50b8a9..3b2174b6 100644 --- a/gpgme/verify.c +++ b/gpgme/verify.c @@ -28,6 +28,7 @@ #include "util.h" #include "context.h" #include "ops.h" +#include "key.h" struct verify_result_s { struct verify_result_s *next; @@ -219,7 +220,7 @@ gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text ) { int rc = 0; int i; - int pipemode = !!text; /* use pipemode for detached sigs */ + int pipemode = 0; /*!!text; use pipemode for detached sigs */ fail_on_pending_request( c ); c->pending = 1; @@ -414,8 +415,7 @@ GpgmeError gpgme_get_sig_key (GpgmeCtx c, int idx, GpgmeKey *r_key) { VerifyResult res; - GpgmeCtx listctx; - GpgmeError err; + GpgmeError err = 0; if (!c || !r_key) return mk_error (Invalid_Value); @@ -430,15 +430,19 @@ gpgme_get_sig_key (GpgmeCtx c, int idx, GpgmeKey *r_key) if (strlen(res->fpr) < 16) /* we have at least an key ID */ return mk_error (Invalid_Key); - /* Fixme: This can me optimized keeping - * an internal context used for such key listings */ - if ( (err=gpgme_new (&listctx)) ) - return err; - gpgme_set_keylist_mode( listctx, c->keylist_mode ); - if ( !(err=gpgme_op_keylist_start (listctx, res->fpr, 0 )) ) - err=gpgme_op_keylist_next ( listctx, r_key ); - gpgme_release (listctx); + *r_key = _gpgme_key_cache_get (res->fpr); + if (!*r_key) { + GpgmeCtx listctx; + /* Fixme: This can be optimized by keeping + * an internal context used for such key listings */ + if ( (err=gpgme_new (&listctx)) ) + return err; + gpgme_set_keylist_mode( listctx, c->keylist_mode ); + if ( !(err=gpgme_op_keylist_start (listctx, res->fpr, 0 )) ) + err=gpgme_op_keylist_next ( listctx, r_key ); + gpgme_release (listctx); + } return err; } diff --git a/gpgme/version.c b/gpgme/version.c index 0d8e5a7c..74b6576d 100644 --- a/gpgme/version.c +++ b/gpgme/version.c @@ -30,7 +30,7 @@ #include "rungpg.h" #include "sema.h" #include "util.h" - +#include "key.h" /* for key_cache_init */ static int lineno; static char *tmp_engine_version; @@ -46,6 +46,7 @@ do_subsystem_inits (void) if (done) return; _gpgme_sema_subsystem_init (); + _gpgme_key_cache_init (); } @@ -104,7 +105,7 @@ compare_versions ( const char *my_version, const char *req_version ) if ( my_major > rq_major || (my_major == rq_major && my_minor > rq_minor) - || (my_major == rq_major && my_minor == rq_minor + || (my_major == rq_major && my_minor == rq_minor && my_micro > rq_micro) || (my_major == rq_major && my_minor == rq_minor && my_micro == rq_micro @@ -173,7 +174,7 @@ gpgme_check_engine () s = strstr (info, ""); if (s) { s += 9; - s2 = strchr (s, '>'); + s2 = strchr (s, '<'); if (s2) { char *ver = xtrymalloc (s2 - s + 1); if (!ver) diff --git a/tests/t-verify.c b/tests/t-verify.c index b315d1f1..524a203e 100644 --- a/tests/t-verify.c +++ b/tests/t-verify.c @@ -132,6 +132,7 @@ main (int argc, char **argv ) GpgmeData sig, text; GpgmeSigStat status; char *nota; + int n = 0; err = gpgme_new (&ctx); fail_if_err (err); @@ -166,6 +167,7 @@ main (int argc, char **argv ) fail_if_err (err); gpgme_data_rewind ( sig ); err = gpgme_op_verify (ctx, sig, text, &status ); + print_sig_stat ( ctx, status ); fail_if_err (err); if ( (nota=gpgme_get_notation (ctx)) ) @@ -174,7 +176,7 @@ main (int argc, char **argv ) gpgme_data_release (sig); gpgme_data_release (text); -} while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); +} while ( argc > 1 && !strcmp( argv[1], "--loop" ) && ++n < 20 ); gpgme_release (ctx); return 0;