doc/
2002-05-09 Marcus Brinkmann <marcus@g10code.de> * gpgme.texi (Overview): Replace note about thread-safeness. (Multi Threading): New section. gpgme/ 2002-05-08 Marcus Brinkmann <marcus@g10code.de> * w32-util.c: New static variable GET_PATH_LOCK. (_gpgme_get_gpg_path): Remove superfluous NULL initializer. Take lock while determining path. (_gpgme_get_gpgsm_path): Likewise. * version.c (do_subsystem_inits): Set DONE to 1 after initialization. (gpgme_get_engine_info): New variable ENGINE_INFO_LOCK. Take lock while determining engine info. * rungpg.c (_gpgme_gpg_get_version): New variable GPG_VERSION_LOCK. Take the lock while determining the program version. * posix-io.c: Include "sema.h". (_gpgme_io_spawn): New variable FIXED_SIGNALS_LOCK. Take the lock while fixing the signals. (_gpgme_io_select): Make READFDS and WRITEFDS non-static. * key.c: Include "sema.h". New globals KEY_CACHE_LOCK and KEY_REF_LOCK. (capabilities_to_string): Make STRINGS very const. (_gpgme_key_cache_add): Lock the key cache. (_gpgme_key_cache_get): Likewise. (gpgme_key_ref, gpgme_key_release): Lock the key_ref_lock. * import.c (append_xml_impinfo): Make IMPORTED_FIELDS and IMPORT_RES_FIELDS very const. Make FIELD and FIELD_NAME a litle const. * engine.c (_gpgme_engine_get_info): New variable ENGINE_INFO_LOCK. Take lock while determining engine info. * engine-gpgsm.c: Include "sema.h". (_gpgme_gpgsm_get_version): New variable GPGSM_VERSION_LOCK. Take lock while getting program version.
This commit is contained in:
parent
d27e6506b1
commit
4e0d4d7cf3
3
TODO
3
TODO
@ -8,8 +8,6 @@ Hey Emacs, this is -*- outline -*- mode!
|
||||
* Allow to use GTK's main loop instead of the select stuff in
|
||||
wait.c
|
||||
|
||||
* add locking to the key cache?
|
||||
|
||||
* cleanup the namespace - we use log_* assuan_* ascii_* mutex_*
|
||||
But those are only used internally. Some linker tricks should make
|
||||
it possible to hide them from the user (didn't work last time, try
|
||||
@ -30,6 +28,7 @@ Hey Emacs, this is -*- outline -*- mode!
|
||||
*** For pipemode, make sure to release the pipemode callback data object.
|
||||
|
||||
* Operations
|
||||
** gpgme_wait needs to be made thread safe!!!
|
||||
** Export status handler need much more work.
|
||||
** Import should return a useful error when one happened.
|
||||
** Genkey should return something more useful than General_Error.
|
||||
|
@ -1,3 +1,8 @@
|
||||
2002-05-09 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* gpgme.texi (Overview): Replace note about thread-safeness.
|
||||
(Multi Threading): New section.
|
||||
|
||||
2002-05-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgme.texi (Manipulating Data Buffers): Changed some data types
|
||||
|
@ -104,6 +104,7 @@ Preparation
|
||||
* Header:: What header file you need to include.
|
||||
* Building the Source:: Compiler options to be used.
|
||||
* Library Version Check:: Getting and verifying the library version.
|
||||
* Multi Threading:: How GPGME can be used in an MT environment.
|
||||
|
||||
Protocols and Engines
|
||||
|
||||
@ -278,11 +279,9 @@ including listing keys, querying their attributes, generating,
|
||||
importing, exporting and deleting keys, and acquiring information
|
||||
about the trust path.
|
||||
|
||||
@cindex thread-safeness
|
||||
@cindex multi-threading
|
||||
@strong{Caution:} The @acronym{GPGME} library is not thread-safe. It
|
||||
will be to some extent in the future, but currently great care has to
|
||||
be taken if @acronym{GPGME} is used in a multi-threaded environment.
|
||||
With some precautions, @acronym{GPGME} can be used in a multi-threaded
|
||||
environment, although it is not completely thread safe and thus needs
|
||||
the support of the application.
|
||||
|
||||
|
||||
@node Preparation
|
||||
@ -298,6 +297,7 @@ of the library are verified.
|
||||
* Header:: What header file you need to include.
|
||||
* Building the Source:: Compiler options to be used.
|
||||
* Library Version Check:: Getting and verifying the library version.
|
||||
* Multi Threading:: How GPGME can be used in an MT environment.
|
||||
@end menu
|
||||
|
||||
|
||||
@ -402,6 +402,81 @@ features are provided by the installed version of the library.
|
||||
@end deftypefun
|
||||
|
||||
|
||||
@node Multi Threading
|
||||
@section Multi Threading
|
||||
@cindex thread-safeness
|
||||
@cindex multi-threading
|
||||
|
||||
The @acronym{GPGME} library is not entirely thread-safe, but it can
|
||||
still be used in a multi-threaded environment if some care is taken.
|
||||
If the following requirements are met, there should be no race
|
||||
conditions to worry about:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
The function @code{gpgme_check_version} must be called before any
|
||||
other function in the library, because it initializes the locking
|
||||
subsystem in @acronym{GPGME}. To achieve this in all generality, it
|
||||
is necessary to synchronize the call to this function with all other
|
||||
calls to functions in the library, using the synchronization
|
||||
mechanisms available in your thread library. Otherwise, specific
|
||||
compiler or CPU memory cache optimizations could lead to the situation
|
||||
where a thread is started and uses @acronym{GPGME} before the effects
|
||||
of the initialization are visible for this thread. It doesn't even
|
||||
suffice to call @code{gpgme_check_version} before creating this other
|
||||
thread@footnote{In SMP systems the new thread could be started on
|
||||
another CPU before the effects of the initialization are seen by that
|
||||
CPU's memory cache. Not doing proper synchronization here leads to
|
||||
the same problems the double-checked locking idiom has. You might
|
||||
find that if you don't do proper synchronization, it still works in
|
||||
most configurations. Don't let this fool you. Someday it might lead
|
||||
to subtle bugs when someone tries it on a DEC Alpha or an SMP
|
||||
machine.}.
|
||||
|
||||
For example, if you are using POSIX threads, each thread that wants to
|
||||
call functions in @acronym{GPGME} could call the following function
|
||||
before any function in the library:
|
||||
|
||||
@example
|
||||
#include <pthread.h>
|
||||
|
||||
void
|
||||
initialize_gpgme (void)
|
||||
{
|
||||
static int gpgme_init;
|
||||
static pthread_mutext_t gpgme_init_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
pthread_mutex_lock (&gpgme_init_lock);
|
||||
if (!gpgme_init)
|
||||
{
|
||||
gpgme_check_version ();
|
||||
gpgme_init = 1;
|
||||
}
|
||||
pthread_mutex_unlock (&gpgme_init_lock);
|
||||
}
|
||||
@end example
|
||||
|
||||
@item
|
||||
Any @code{GpgmeData}, @code{GpgmeCtx} and @code{GpgmeRecipients}
|
||||
object must only be accessed by one thread at a time. If multiple
|
||||
threads want to deal with the same object, the caller has to make sure
|
||||
that operations on this object are fully synchronized.
|
||||
|
||||
@item
|
||||
Only one thread is allowed to call @code{gpgme_wait} at a time. If
|
||||
multiple threads call this function, the caller must make sure that
|
||||
all invocations are fully synchronized.
|
||||
|
||||
@item
|
||||
Unfortunately, the last rule implies that all calls to one of the
|
||||
following functions have to be fully synchronized together with
|
||||
@code{gpgme_wait}, as they call @code{gpgme_wait} internally: All
|
||||
functions @code{gpgme_op_FOO} that have a corresponding
|
||||
@code{gpgme_op_FOO_start} function, @code{gpgme_op_keylist_next},
|
||||
@code{gpgme_op_trustlist_next}.
|
||||
@end itemize
|
||||
|
||||
|
||||
@node Protocols and Engines
|
||||
@chapter Protocols and Engines
|
||||
@cindex protocol
|
||||
|
@ -1,3 +1,35 @@
|
||||
2002-05-08 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* w32-util.c: New static variable GET_PATH_LOCK.
|
||||
(_gpgme_get_gpg_path): Remove superfluous NULL initializer.
|
||||
Take lock while determining path.
|
||||
(_gpgme_get_gpgsm_path): Likewise.
|
||||
* version.c (do_subsystem_inits): Set DONE to 1 after
|
||||
initialization.
|
||||
(gpgme_get_engine_info): New variable ENGINE_INFO_LOCK. Take lock
|
||||
while determining engine info.
|
||||
* rungpg.c (_gpgme_gpg_get_version): New variable
|
||||
GPG_VERSION_LOCK. Take the lock while determining the program
|
||||
version.
|
||||
* posix-io.c: Include "sema.h".
|
||||
(_gpgme_io_spawn): New variable FIXED_SIGNALS_LOCK. Take the lock
|
||||
while fixing the signals.
|
||||
(_gpgme_io_select): Make READFDS and WRITEFDS non-static.
|
||||
* key.c: Include "sema.h". New globals KEY_CACHE_LOCK and
|
||||
KEY_REF_LOCK.
|
||||
(capabilities_to_string): Make STRINGS very const.
|
||||
(_gpgme_key_cache_add): Lock the key cache.
|
||||
(_gpgme_key_cache_get): Likewise.
|
||||
(gpgme_key_ref, gpgme_key_release): Lock the key_ref_lock.
|
||||
* import.c (append_xml_impinfo): Make IMPORTED_FIELDS and
|
||||
IMPORT_RES_FIELDS very const. Make FIELD and FIELD_NAME a litle
|
||||
const.
|
||||
* engine.c (_gpgme_engine_get_info): New variable
|
||||
ENGINE_INFO_LOCK. Take lock while determining engine info.
|
||||
* engine-gpgsm.c: Include "sema.h".
|
||||
(_gpgme_gpgsm_get_version): New variable GPGSM_VERSION_LOCK. Take
|
||||
lock while getting program version.
|
||||
|
||||
2002-05-08 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* debug.h: New file.
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "wait.h"
|
||||
#include "io.h"
|
||||
#include "key.h"
|
||||
#include "sema.h"
|
||||
|
||||
#include "engine-gpgsm.h"
|
||||
|
||||
@ -99,10 +100,12 @@ const char *
|
||||
_gpgme_gpgsm_get_version (void)
|
||||
{
|
||||
static const char *gpgsm_version;
|
||||
DEFINE_STATIC_LOCK (gpgsm_version_lock);
|
||||
|
||||
/* FIXME: Locking. */
|
||||
LOCK (gpgsm_version_lock);
|
||||
if (!gpgsm_version)
|
||||
gpgsm_version = _gpgme_get_program_version (_gpgme_get_gpgsm_path ());
|
||||
UNLOCK (gpgsm_version_lock);
|
||||
|
||||
return gpgsm_version;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "rungpg.h"
|
||||
#include "engine-gpgsm.h"
|
||||
|
||||
|
||||
struct engine_object_s
|
||||
{
|
||||
GpgmeProtocol protocol;
|
||||
@ -50,6 +51,7 @@ struct engine_object_s
|
||||
} engine;
|
||||
};
|
||||
|
||||
|
||||
struct reap_s
|
||||
{
|
||||
struct reap_s *next;
|
||||
@ -61,6 +63,7 @@ struct reap_s
|
||||
static struct reap_s *reap_list;
|
||||
DEFINE_STATIC_LOCK (reap_list_lock);
|
||||
|
||||
|
||||
/* Get the path of the engine for PROTOCOL. */
|
||||
const char *
|
||||
_gpgme_engine_get_path (GpgmeProtocol proto)
|
||||
@ -76,6 +79,7 @@ _gpgme_engine_get_path (GpgmeProtocol proto)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the version number of the engine for PROTOCOL. */
|
||||
const char *
|
||||
_gpgme_engine_get_version (GpgmeProtocol proto)
|
||||
@ -91,6 +95,7 @@ _gpgme_engine_get_version (GpgmeProtocol proto)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GpgmeError
|
||||
gpgme_engine_check_version (GpgmeProtocol proto)
|
||||
{
|
||||
@ -105,6 +110,7 @@ gpgme_engine_check_version (GpgmeProtocol proto)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
_gpgme_engine_get_info (GpgmeProtocol proto)
|
||||
{
|
||||
@ -115,25 +121,21 @@ _gpgme_engine_get_info (GpgmeProtocol proto)
|
||||
" </engine>\n";
|
||||
static const char *const strproto[3] = { "OpenPGP", "CMS", NULL };
|
||||
static const char *engine_info[3]; /* FIXME: MAX_PROTO + 1*/
|
||||
const char *path;
|
||||
const char *version;
|
||||
char *info;
|
||||
DEFINE_STATIC_LOCK (engine_info_lock);
|
||||
|
||||
if (proto > 2 /* FIXME MAX_PROTO */ || !strproto[proto])
|
||||
return NULL;
|
||||
|
||||
/* FIXME: Make sure that only one instance does run. */
|
||||
if (engine_info[proto])
|
||||
return engine_info[proto];
|
||||
LOCK (engine_info_lock);
|
||||
if (!engine_info[proto])
|
||||
{
|
||||
const char *path = _gpgme_engine_get_path (proto);
|
||||
const char *version = _gpgme_engine_get_version (proto);
|
||||
|
||||
path = _gpgme_engine_get_path (proto);
|
||||
version = _gpgme_engine_get_version (proto);
|
||||
|
||||
if (!path || !version)
|
||||
return NULL;
|
||||
|
||||
info = xtrymalloc (strlen(fmt) + strlen(strproto[proto]) + strlen(path)
|
||||
+ strlen (version) + 1);
|
||||
if (path && version)
|
||||
{
|
||||
char *info = xtrymalloc (strlen (fmt) + strlen (strproto[proto])
|
||||
+ strlen (path) + strlen (version) + 1);
|
||||
if (!info)
|
||||
info = " <engine>\n"
|
||||
" <error>Out of core</error>\n"
|
||||
@ -141,10 +143,13 @@ _gpgme_engine_get_info (GpgmeProtocol proto)
|
||||
else
|
||||
sprintf (info, fmt, strproto[proto], version, path);
|
||||
engine_info[proto] = info;
|
||||
|
||||
}
|
||||
}
|
||||
UNLOCK (engine_info_lock);
|
||||
return engine_info[proto];
|
||||
}
|
||||
|
||||
|
||||
GpgmeError
|
||||
_gpgme_engine_new (GpgmeProtocol proto, EngineObject *r_engine)
|
||||
{
|
||||
@ -193,6 +198,7 @@ _gpgme_engine_new (GpgmeProtocol proto, EngineObject *r_engine)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_gpgme_engine_release (EngineObject engine)
|
||||
{
|
||||
@ -561,6 +567,7 @@ _gpgme_engine_start (EngineObject engine, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ extern "C" {
|
||||
AM_PATH_GPGME macro) check that this header matches the installed
|
||||
library. Warning: Do not edit the next line. configure will do
|
||||
that for you! */
|
||||
#define GPGME_VERSION "0.3.6"
|
||||
#define GPGME_VERSION "0.3.7-cvs"
|
||||
|
||||
|
||||
/* The opaque data types used by GPGME. */
|
||||
|
@ -53,14 +53,14 @@ static void
|
||||
append_xml_impinfo (GpgmeData *rdh, GpgStatusCode code, char *args)
|
||||
{
|
||||
#define MAX_IMPORTED_FIELDS 14
|
||||
static char *imported_fields[MAX_IMPORTED_FIELDS]
|
||||
static const char *const imported_fields[MAX_IMPORTED_FIELDS]
|
||||
= { "keyid", "username", 0 };
|
||||
static char *import_res_fields[MAX_IMPORTED_FIELDS]
|
||||
static const char *const import_res_fields[MAX_IMPORTED_FIELDS]
|
||||
= { "count", "no_user_id", "imported", "imported_rsa",
|
||||
"unchanged", "n_uids", "n_subk", "n_sigs", "s_sigsn_revoc",
|
||||
"sec_read", "sec_imported", "sec_dups", "skipped_new", 0 };
|
||||
char *field[MAX_IMPORTED_FIELDS];
|
||||
char **field_name = 0;
|
||||
const char *field[MAX_IMPORTED_FIELDS];
|
||||
const char *const *field_name = 0;
|
||||
GpgmeData dh;
|
||||
int i;
|
||||
|
||||
|
276
gpgme/key.c
276
gpgme/key.c
@ -28,6 +28,7 @@
|
||||
#include "util.h"
|
||||
#include "ops.h"
|
||||
#include "key.h"
|
||||
#include "sema.h"
|
||||
|
||||
#define ALLOC_CHUNK 1024
|
||||
#define my_isdigit(a) ((a) >='0' && (a) <= '9')
|
||||
@ -36,17 +37,25 @@
|
||||
#error unsigned int too short to be used as a hash value
|
||||
#endif
|
||||
|
||||
struct key_cache_item_s {
|
||||
struct key_cache_item_s
|
||||
{
|
||||
struct key_cache_item_s *next;
|
||||
GpgmeKey key;
|
||||
};
|
||||
|
||||
/* Protects all key_cache_* variables. */
|
||||
DEFINE_STATIC_LOCK (key_cache_lock);
|
||||
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;
|
||||
|
||||
/* Protects all reference counters in keys. All other accesses to a
|
||||
key are either read only or happen before the key is entered into
|
||||
the cache. */
|
||||
DEFINE_STATIC_LOCK (key_ref_lock);
|
||||
|
||||
static int
|
||||
hextobyte (const byte *s)
|
||||
{
|
||||
@ -78,14 +87,19 @@ hash_key (const char *fpr, unsigned int *rhash)
|
||||
unsigned int hash;
|
||||
int c;
|
||||
|
||||
if ( !fpr ) return -1;
|
||||
if ( (c = hextobyte(fpr)) == -1 ) return -1;
|
||||
if (!fpr)
|
||||
return -1;
|
||||
if ((c = hextobyte (fpr)) == -1)
|
||||
return -1;
|
||||
hash = c;
|
||||
if ( (c = hextobyte(fpr+2)) == -1 ) return -1;
|
||||
if ((c = hextobyte (fpr+2)) == -1)
|
||||
return -1;
|
||||
hash |= c << 8;
|
||||
if ( (c = hextobyte(fpr+4)) == -1 ) return -1;
|
||||
if ((c = hextobyte (fpr+4)) == -1)
|
||||
return -1;
|
||||
hash |= c << 16;
|
||||
if ( (c = hextobyte(fpr+6)) == -1 ) return -1;
|
||||
if ((c = hextobyte (fpr+6)) == -1)
|
||||
return -1;
|
||||
hash |= c << 24;
|
||||
|
||||
*rhash = hash;
|
||||
@ -95,22 +109,26 @@ hash_key (const char *fpr, unsigned int *rhash)
|
||||
void
|
||||
_gpgme_key_cache_init (void)
|
||||
{
|
||||
if (key_cache_initialized)
|
||||
return;
|
||||
LOCK (key_cache_lock);
|
||||
if (!key_cache_initialized)
|
||||
{
|
||||
key_cache_size = 503;
|
||||
key_cache = xtrycalloc (key_cache_size, sizeof *key_cache);
|
||||
if (!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
|
||||
*/
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
UNLOCK (key_cache_lock);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
@ -121,15 +139,20 @@ _gpgme_key_cache_add (GpgmeKey key)
|
||||
if (!key)
|
||||
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 ) {
|
||||
LOCK (key_cache_lock);
|
||||
/* Check if cache was enabled. */
|
||||
if (!key_cache_size)
|
||||
{
|
||||
UNLOCK (key_cache_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@ -138,18 +161,22 @@ _gpgme_key_cache_add (GpgmeKey key)
|
||||
continue;
|
||||
|
||||
hash %= key_cache_size;
|
||||
for (item=key_cache[hash],n=0; item; item = item->next, n++) {
|
||||
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 */
|
||||
/* Already in cache. */
|
||||
break;
|
||||
/* 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);
|
||||
UNLOCK (key_cache_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -157,20 +184,24 @@ _gpgme_key_cache_add (GpgmeKey key)
|
||||
if (item)
|
||||
continue;
|
||||
|
||||
if (n > key_cache_max_chain_length ) { /* remove the last entries */
|
||||
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++ ) {
|
||||
last = item, item = item->next, n++)
|
||||
;
|
||||
}
|
||||
if (last) {
|
||||
|
||||
if (last)
|
||||
{
|
||||
struct key_cache_item_s *next;
|
||||
|
||||
assert (last->next == item);
|
||||
last->next = NULL;
|
||||
for ( ;item; item=next) {
|
||||
for (; item; item = next)
|
||||
{
|
||||
next = item->next;
|
||||
gpgme_key_unref (item->key);
|
||||
item->key = NULL;
|
||||
@ -181,14 +212,19 @@ _gpgme_key_cache_add (GpgmeKey key)
|
||||
}
|
||||
|
||||
item = key_cache_unused_items;
|
||||
if (item) {
|
||||
if (item)
|
||||
{
|
||||
key_cache_unused_items = item->next;
|
||||
item->next = NULL;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
item = xtrymalloc (sizeof *item);
|
||||
if (!item)
|
||||
return; /* out of core */
|
||||
{
|
||||
UNLOCK (key_cache_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
item->key = key;
|
||||
@ -196,6 +232,7 @@ _gpgme_key_cache_add (GpgmeKey key)
|
||||
item->next = key_cache[hash];
|
||||
key_cache[hash] = item;
|
||||
}
|
||||
UNLOCK (key_cache_lock);
|
||||
}
|
||||
|
||||
|
||||
@ -205,23 +242,36 @@ _gpgme_key_cache_get (const char *fpr)
|
||||
struct key_cache_item_s *item;
|
||||
unsigned int hash;
|
||||
|
||||
LOCK (key_cache_lock);
|
||||
/* Check if cache is enabled already. */
|
||||
if (!key_cache_size)
|
||||
return NULL; /* cache not (yet) enabled */
|
||||
{
|
||||
UNLOCK (key_cache_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hash_key (fpr, &hash))
|
||||
{
|
||||
UNLOCK (key_cache_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hash %= key_cache_size;
|
||||
for (item=key_cache[hash]; item; item = item->next) {
|
||||
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) ) {
|
||||
for (k = &item->key->keys; k; k = k->next)
|
||||
{
|
||||
if (k->fingerprint && !strcmp (k->fingerprint, fpr))
|
||||
{
|
||||
gpgme_key_ref (item->key);
|
||||
UNLOCK (key_cache_lock);
|
||||
return item->key;
|
||||
}
|
||||
}
|
||||
}
|
||||
UNLOCK (key_cache_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -229,14 +279,19 @@ _gpgme_key_cache_get (const char *fpr)
|
||||
static const char *
|
||||
pkalgo_to_string (int algo)
|
||||
{
|
||||
switch (algo) {
|
||||
switch (algo)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3: return "RSA";
|
||||
case 3:
|
||||
return "RSA";
|
||||
case 16:
|
||||
case 20: return "ElG";
|
||||
case 17: return "DSA";
|
||||
default: return "Unknown";
|
||||
case 20:
|
||||
return "ElG";
|
||||
case 17:
|
||||
return "DSA";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,7 +336,9 @@ void
|
||||
gpgme_key_ref (GpgmeKey key)
|
||||
{
|
||||
return_if_fail (key);
|
||||
LOCK (key_ref_lock);
|
||||
key->ref_count++;
|
||||
UNLOCK (key_ref_lock);
|
||||
}
|
||||
|
||||
|
||||
@ -296,7 +353,8 @@ add_subkey (GpgmeKey key, int secret)
|
||||
|
||||
if(!(kk = key->keys.next))
|
||||
key->keys.next = k;
|
||||
else {
|
||||
else
|
||||
{
|
||||
while (kk->next)
|
||||
kk = kk->next;
|
||||
kk->next = k;
|
||||
@ -306,12 +364,14 @@ add_subkey (GpgmeKey key, int secret)
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
struct subkey_s *
|
||||
_gpgme_key_add_subkey (GpgmeKey key)
|
||||
{
|
||||
return add_subkey (key, 0);
|
||||
}
|
||||
|
||||
|
||||
struct subkey_s *
|
||||
_gpgme_key_add_secret_subkey (GpgmeKey key)
|
||||
{
|
||||
@ -319,7 +379,6 @@ _gpgme_key_add_secret_subkey (GpgmeKey key)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* gpgme_key_release:
|
||||
* @key: Key Object or NULL
|
||||
@ -338,17 +397,24 @@ gpgme_key_release ( GpgmeKey key )
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
LOCK (key_ref_lock);
|
||||
assert (key->ref_count);
|
||||
if (--key->ref_count)
|
||||
{
|
||||
UNLOCK (key_ref_lock);
|
||||
return;
|
||||
}
|
||||
UNLOCK (key_ref_lock);
|
||||
|
||||
xfree (key->keys.fingerprint);
|
||||
for (k = key->keys.next; k; k = k2 ) {
|
||||
for (k = key->keys.next; k; k = k2)
|
||||
{
|
||||
k2 = k->next;
|
||||
xfree (k->fingerprint);
|
||||
xfree (k);
|
||||
}
|
||||
for (u = key->uids; u; u = u2 ) {
|
||||
for (u = key->uids; u; u = u2)
|
||||
{
|
||||
u2 = u->next;
|
||||
xfree (u);
|
||||
}
|
||||
@ -391,34 +457,47 @@ parse_user_id ( struct user_id_s *uid, char *tail )
|
||||
int in_email = 0;
|
||||
int in_comment = 0;
|
||||
|
||||
for (s=uid->name; *s; s++ ) {
|
||||
if ( in_email ) {
|
||||
for (s = uid->name; *s; s++)
|
||||
{
|
||||
if (in_email)
|
||||
{
|
||||
if (*s == '<')
|
||||
in_email++; /* not legal but anyway */
|
||||
else if (*s== '>') {
|
||||
if ( !--in_email ) {
|
||||
if (!uid->email_part) {
|
||||
/* Not legal but anyway. */
|
||||
in_email++;
|
||||
else if (*s == '>')
|
||||
{
|
||||
if (!--in_email)
|
||||
{
|
||||
if (!uid->email_part)
|
||||
{
|
||||
uid->email_part = tail;
|
||||
tail = set_user_id_part ( tail, start, s-start );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( in_comment ) {
|
||||
else if (in_comment)
|
||||
{
|
||||
if (*s == '(')
|
||||
in_comment++;
|
||||
else if (*s== ')') {
|
||||
if ( !--in_comment ) {
|
||||
if (!uid->comment_part) {
|
||||
else if (*s== ')')
|
||||
{
|
||||
if (!--in_comment)
|
||||
{
|
||||
if (!uid->comment_part)
|
||||
{
|
||||
uid->comment_part = tail;
|
||||
tail = set_user_id_part ( tail, start, s-start );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( *s == '<' ) {
|
||||
if ( in_name ) {
|
||||
if ( !uid->name_part ) {
|
||||
else if (*s == '<')
|
||||
{
|
||||
if (in_name)
|
||||
{
|
||||
if (!uid->name_part)
|
||||
{
|
||||
uid->name_part = tail;
|
||||
tail = set_user_id_part (tail, start, s-start);
|
||||
}
|
||||
@ -427,9 +506,12 @@ parse_user_id ( struct user_id_s *uid, char *tail )
|
||||
in_email = 1;
|
||||
start = s+1;
|
||||
}
|
||||
else if ( *s == '(' ) {
|
||||
if ( in_name ) {
|
||||
if ( !uid->name_part ) {
|
||||
else if (*s == '(')
|
||||
{
|
||||
if (in_name)
|
||||
{
|
||||
if (!uid->name_part)
|
||||
{
|
||||
uid->name_part = tail;
|
||||
tail = set_user_id_part (tail, start, s-start );
|
||||
}
|
||||
@ -438,20 +520,23 @@ parse_user_id ( struct user_id_s *uid, char *tail )
|
||||
in_comment = 1;
|
||||
start = s+1;
|
||||
}
|
||||
else if ( !in_name && *s != ' ' && *s != '\t' ) {
|
||||
else if (!in_name && *s != ' ' && *s != '\t')
|
||||
{
|
||||
in_name = 1;
|
||||
start = s;
|
||||
}
|
||||
}
|
||||
|
||||
if ( in_name ) {
|
||||
if ( !uid->name_part ) {
|
||||
if (in_name)
|
||||
{
|
||||
if (!uid->name_part)
|
||||
{
|
||||
uid->name_part = tail;
|
||||
tail = set_user_id_part (tail, start, s-start);
|
||||
}
|
||||
}
|
||||
|
||||
/* let unused parts point to an EOS */
|
||||
/* Let unused parts point to an EOS. */
|
||||
tail--;
|
||||
if (!uid->name_part)
|
||||
uid->name_part = tail;
|
||||
@ -459,7 +544,6 @@ parse_user_id ( struct user_id_s *uid, char *tail )
|
||||
uid->email_part = tail;
|
||||
if (!uid->comment_part)
|
||||
uid->comment_part = tail;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -471,7 +555,7 @@ parse_x509_user_id ( struct user_id_s *uid, char *tail )
|
||||
if (*s == '<' && s[strlen (s) - 1] == '>')
|
||||
uid->email_part = s;
|
||||
|
||||
/* let unused parts point to an EOS */
|
||||
/* Let unused parts point to an EOS. */
|
||||
tail--;
|
||||
if (!uid->name_part)
|
||||
uid->name_part = tail;
|
||||
@ -699,7 +783,7 @@ gpgme_key_get_as_xml ( GpgmeKey key )
|
||||
for (u = key->uids; u; u = u->next)
|
||||
one_uid_as_xml (d,u);
|
||||
|
||||
/* and now the subkeys */
|
||||
/* And now the subkeys. */
|
||||
for (k = key->keys.next; k; k = k->next)
|
||||
{
|
||||
_gpgme_data_append_string (d, " <subkey>\n");
|
||||
@ -731,7 +815,8 @@ gpgme_key_get_as_xml ( GpgmeKey key )
|
||||
static const char *
|
||||
capabilities_to_string (struct subkey_s *k)
|
||||
{
|
||||
static char *strings[8] = {
|
||||
static const char *const strings[8] =
|
||||
{
|
||||
"",
|
||||
"c",
|
||||
"s",
|
||||
@ -747,7 +832,6 @@ capabilities_to_string (struct subkey_s *k)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* gpgme_key_get_string_attr:
|
||||
* @key: Key Object
|
||||
@ -778,7 +862,8 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what,
|
||||
if (idx < 0)
|
||||
return NULL;
|
||||
|
||||
switch (what) {
|
||||
switch (what)
|
||||
{
|
||||
case GPGME_ATTR_KEYID:
|
||||
for (k = &key->keys; k && idx; k = k->next, idx--)
|
||||
;
|
||||
@ -800,7 +885,8 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what,
|
||||
case GPGME_ATTR_LEN:
|
||||
case GPGME_ATTR_CREATED:
|
||||
case GPGME_ATTR_EXPIRE:
|
||||
break; /* use another get function */
|
||||
/* Use another get function. */
|
||||
break;
|
||||
case GPGME_ATTR_OTRUST:
|
||||
val = "[fixme]";
|
||||
break;
|
||||
@ -827,18 +913,32 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what,
|
||||
case GPGME_ATTR_VALIDITY:
|
||||
for (u = key->uids; u && idx; u = u->next, idx--)
|
||||
;
|
||||
if (u) {
|
||||
switch (u->validity) {
|
||||
case GPGME_VALIDITY_UNKNOWN: val = "?"; break;
|
||||
case GPGME_VALIDITY_UNDEFINED: val = "q"; break;
|
||||
case GPGME_VALIDITY_NEVER: val = "n"; break;
|
||||
case GPGME_VALIDITY_MARGINAL: val = "m"; break;
|
||||
case GPGME_VALIDITY_FULL: val = "f"; break;
|
||||
case GPGME_VALIDITY_ULTIMATE: val = "u"; break;
|
||||
if (u)
|
||||
{
|
||||
switch (u->validity)
|
||||
{
|
||||
case GPGME_VALIDITY_UNKNOWN:
|
||||
val = "?";
|
||||
break;
|
||||
case GPGME_VALIDITY_UNDEFINED:
|
||||
val = "q";
|
||||
break;
|
||||
case GPGME_VALIDITY_NEVER:
|
||||
val = "n";
|
||||
break;
|
||||
case GPGME_VALIDITY_MARGINAL:
|
||||
val = "m";
|
||||
break;
|
||||
case GPGME_VALIDITY_FULL:
|
||||
val = "f";
|
||||
break;
|
||||
case GPGME_VALIDITY_ULTIMATE:
|
||||
val = "u";
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GPGME_ATTR_LEVEL: /* not used here */
|
||||
case GPGME_ATTR_LEVEL:
|
||||
case GPGME_ATTR_TYPE:
|
||||
case GPGME_ATTR_KEY_REVOKED:
|
||||
case GPGME_ATTR_KEY_INVALID:
|
||||
@ -849,6 +949,7 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what,
|
||||
case GPGME_ATTR_CAN_ENCRYPT:
|
||||
case GPGME_ATTR_CAN_SIGN:
|
||||
case GPGME_ATTR_CAN_CERTIFY:
|
||||
/* Not used here. */
|
||||
break;
|
||||
case GPGME_ATTR_IS_SECRET:
|
||||
if (key->secret)
|
||||
@ -870,7 +971,7 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what,
|
||||
val = key->chain_id;
|
||||
break;
|
||||
case GPGME_ATTR_SIG_STATUS:
|
||||
/* not of any use here */
|
||||
/* Not of any use here. */
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
@ -908,7 +1009,8 @@ gpgme_key_get_ulong_attr ( GpgmeKey key, GpgmeAttr what,
|
||||
if (idx < 0)
|
||||
return 0;
|
||||
|
||||
switch (what) {
|
||||
switch (what)
|
||||
{
|
||||
case GPGME_ATTR_ALGO:
|
||||
for (k = &key->keys; k && idx; k=k->next, idx--)
|
||||
;
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "io.h"
|
||||
#include "sema.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
@ -149,10 +150,12 @@ _gpgme_io_spawn (const char *path, char **argv,
|
||||
struct spawn_fd_item_s *fd_child_list,
|
||||
struct spawn_fd_item_s *fd_parent_list)
|
||||
{
|
||||
static volatile int fixed_signals;
|
||||
static int fixed_signals;
|
||||
DEFINE_STATIC_LOCK (fixed_signals_lock);
|
||||
pid_t pid;
|
||||
int i;
|
||||
|
||||
LOCK (fixed_signals_lock);
|
||||
if (!fixed_signals)
|
||||
{
|
||||
struct sigaction act;
|
||||
@ -166,8 +169,8 @@ _gpgme_io_spawn (const char *path, char **argv,
|
||||
sigaction (SIGPIPE, &act, NULL);
|
||||
}
|
||||
fixed_signals = 1;
|
||||
/* XXX: This is not really MT safe. */
|
||||
}
|
||||
UNLOCK (fixed_signals_lock);
|
||||
|
||||
pid = fork ();
|
||||
if (pid == -1)
|
||||
@ -285,8 +288,8 @@ _gpgme_io_kill (int pid, int hard)
|
||||
int
|
||||
_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds)
|
||||
{
|
||||
static fd_set readfds;
|
||||
static fd_set writefds;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
int any, i, max_fd, n, count;
|
||||
struct timeval timeout = { 1, 0 }; /* Use a 1s timeout. */
|
||||
void *dbg_help = NULL;
|
||||
|
@ -167,11 +167,12 @@ const char *
|
||||
_gpgme_gpg_get_version (void)
|
||||
{
|
||||
static const char *gpg_version;
|
||||
DEFINE_STATIC_LOCK (gpg_version_lock);
|
||||
|
||||
/* FIXME: Locking. */
|
||||
LOCK (gpg_version_lock);
|
||||
if (!gpg_version)
|
||||
gpg_version = _gpgme_get_program_version (_gpgme_get_gpg_path ());
|
||||
|
||||
UNLOCK (gpg_version_lock);
|
||||
return gpg_version;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ do_subsystem_inits (void)
|
||||
return;
|
||||
_gpgme_sema_subsystem_init ();
|
||||
_gpgme_key_cache_init ();
|
||||
done = 1;
|
||||
}
|
||||
|
||||
static const char*
|
||||
@ -148,14 +149,15 @@ const char *
|
||||
gpgme_get_engine_info ()
|
||||
{
|
||||
static const char *engine_info;
|
||||
DEFINE_STATIC_LOCK (engine_info_lock);
|
||||
|
||||
LOCK (engine_info_lock);
|
||||
if (!engine_info)
|
||||
{
|
||||
const char *openpgp_info = _gpgme_engine_get_info (GPGME_PROTOCOL_OpenPGP);
|
||||
const char *cms_info = _gpgme_engine_get_info (GPGME_PROTOCOL_CMS);
|
||||
char *info;
|
||||
|
||||
/* FIXME: Make sure that only one instance does run. */
|
||||
if (engine_info)
|
||||
return engine_info;
|
||||
|
||||
if (!openpgp_info && !cms_info)
|
||||
info = "<EngineInfo>\n</EngineInfo>\n";
|
||||
else if (!openpgp_info || !cms_info)
|
||||
@ -164,7 +166,8 @@ gpgme_get_engine_info ()
|
||||
"%s"
|
||||
"</EngineInfo>\n";
|
||||
|
||||
info = xtrymalloc (strlen(fmt) + strlen(openpgp_info
|
||||
info = xtrymalloc (strlen (fmt)
|
||||
+ strlen (openpgp_info
|
||||
? openpgp_info : cms_info) + 1);
|
||||
if (info)
|
||||
sprintf (info, fmt, openpgp_info ? openpgp_info : cms_info);
|
||||
@ -184,9 +187,12 @@ gpgme_get_engine_info ()
|
||||
" <error>Out of core</error>\n"
|
||||
"</EngineInfo>\n";
|
||||
engine_info = info;
|
||||
}
|
||||
UNLOCK (engine_info_lock);
|
||||
return engine_info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gpgme_check_engine:
|
||||
*
|
||||
|
@ -37,6 +37,8 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
DEFINE_STATIC_LOCK (get_path_lock);
|
||||
|
||||
/* Return a string from the Win32 Registry or NULL in case of error.
|
||||
Caller must release the return value. A NULL for root is an alias
|
||||
for HKEY_CURRENT_USER. */
|
||||
@ -112,27 +114,31 @@ find_program_in_registry (const char *name)
|
||||
const char *
|
||||
_gpgme_get_gpg_path (void)
|
||||
{
|
||||
static char *gpg_program = NULL;
|
||||
static char *gpg_program;
|
||||
|
||||
LOCK (get_path_lock);
|
||||
if (!gpg_program)
|
||||
gpg_program = find_program_in_registry ("gpgProgram");
|
||||
#ifdef GPG_PATH
|
||||
if (!gpg_program)
|
||||
gpg_program = GPG_PATH;
|
||||
#endif
|
||||
UNLOCK (get_path_lock);
|
||||
return gpg_program;
|
||||
}
|
||||
|
||||
const char *
|
||||
_gpgme_get_gpgsm_path (void)
|
||||
{
|
||||
static char *gpgsm_program = NULL;
|
||||
static char *gpgsm_program;
|
||||
|
||||
LOCK (get_path_lock);
|
||||
if (!gpgsm_program)
|
||||
gpgsm_program = find_program_in_registry ("gpgsmProgram");
|
||||
#ifdef GPGSM_PATH
|
||||
if (!gpgsm_program)
|
||||
gpgsm_program = GPGSM_PATH;
|
||||
#endif
|
||||
UNLOCK (get_path_lock);
|
||||
return gpgsm_program;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user