diff --git a/TODO b/TODO index 07d0cbaa..6bcd6593 100644 --- a/TODO +++ b/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. diff --git a/doc/ChangeLog b/doc/ChangeLog index 19b141e5..a5c7c5e0 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2002-05-09 Marcus Brinkmann + + * gpgme.texi (Overview): Replace note about thread-safeness. + (Multi Threading): New section. + 2002-05-03 Werner Koch * gpgme.texi (Manipulating Data Buffers): Changed some data types diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 0061274b..9606eedd 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -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 + +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 diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 200dfea0..0696272e 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,35 @@ +2002-05-08 Marcus Brinkmann + + * 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 * debug.h: New file. diff --git a/gpgme/engine-gpgsm.c b/gpgme/engine-gpgsm.c index 7ecbf43d..bb2e5530 100644 --- a/gpgme/engine-gpgsm.c +++ b/gpgme/engine-gpgsm.c @@ -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; } diff --git a/gpgme/engine.c b/gpgme/engine.c index c1dd630e..ce5164b6 100644 --- a/gpgme/engine.c +++ b/gpgme/engine.c @@ -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,36 +121,35 @@ _gpgme_engine_get_info (GpgmeProtocol proto) " \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]; - - 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 (!info) - info = " \n" - " Out of core\n" - " "; - else - sprintf (info, fmt, strproto[proto], version, path); - engine_info[proto] = info; + LOCK (engine_info_lock); + if (!engine_info[proto]) + { + const char *path = _gpgme_engine_get_path (proto); + const char *version = _gpgme_engine_get_version (proto); + if (path && version) + { + char *info = xtrymalloc (strlen (fmt) + strlen (strproto[proto]) + + strlen (path) + strlen (version) + 1); + if (!info) + info = " \n" + " Out of core\n" + " "; + 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) { @@ -572,10 +579,10 @@ _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid) memset (child, 0, sizeof *child); child->pid = pid; child->entered = time (NULL); - LOCK(reap_list_lock); + LOCK (reap_list_lock); child->next = reap_list; reap_list = child; - UNLOCK(reap_list_lock); + UNLOCK (reap_list_lock); } static void diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 71b29565..74487c89 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -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. */ diff --git a/gpgme/import.c b/gpgme/import.c index 6d070510..338cc1d8 100644 --- a/gpgme/import.c +++ b/gpgme/import.c @@ -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; diff --git a/gpgme/key.c b/gpgme/key.c index 01506de3..0b3b787f 100644 --- a/gpgme/key.c +++ b/gpgme/key.c @@ -28,245 +28,300 @@ #include "util.h" #include "ops.h" #include "key.h" +#include "sema.h" #define ALLOC_CHUNK 1024 -#define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) +#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; +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; -static int -hextobyte ( const byte *s ) -{ - int c; +/* 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); - 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 +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; + 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; + 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; + *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; + LOCK (key_cache_lock); + if (!key_cache_initialized) + { + key_cache_size = 503; + key_cache = xtrycalloc (key_cache_size, sizeof *key_cache); + if (!key_cache) + { + key_cache_size = 0; + key_cache_initialized = 1; + } + 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; + } } - /* - * 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 _gpgme_key_cache_add (GpgmeKey key) { - struct subkey_s *k; + struct subkey_s *k; - if (!key) - return; + if (!key) + return; - /* FIXME: add locking */ - if (!key_cache_initialized) - _gpgme_key_cache_init (); - if (!key_cache_size) - return; /* cache was not enabled */ + _gpgme_key_cache_init (); - /* 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; + 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; + + 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) + /* 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; + } + } + } + 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) + { + UNLOCK (key_cache_lock); + return; + } + } + + item->key = key; + gpgme_key_ref (key); + item->next = key_cache[hash]; + key_cache[hash] = item; + } + UNLOCK (key_cache_lock); } GpgmeKey _gpgme_key_cache_get (const char *fpr) { - struct key_cache_item_s *item; - unsigned int hash; + struct key_cache_item_s *item; + unsigned int hash; - if (!key_cache_size) - return NULL; /* cache not (yet) enabled */ + LOCK (key_cache_lock); + /* Check if cache is enabled already. */ + if (!key_cache_size) + { + UNLOCK (key_cache_lock); + return NULL; + } - if (hash_key (fpr, &hash)) - 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) { - struct subkey_s *k; + 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; + 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; } } } - return NULL; + UNLOCK (key_cache_lock); + return NULL; } static const char * -pkalgo_to_string ( int algo ) +pkalgo_to_string (int algo) { - switch (algo) { - case 1: - case 2: - case 3: return "RSA"; - case 16: - case 20: return "ElG"; - case 17: return "DSA"; - default: return "Unknown"; + switch (algo) + { + case 1: + case 2: + case 3: + return "RSA"; + case 16: + case 20: + return "ElG"; + case 17: + return "DSA"; + default: + return "Unknown"; } } static GpgmeError -key_new ( GpgmeKey *r_key, int secret ) +key_new (GpgmeKey *r_key, int secret) { - GpgmeKey key; + GpgmeKey key; - *r_key = NULL; - key = xtrycalloc ( 1, sizeof *key ); - if (!key) - return mk_error (Out_Of_Core); - key->ref_count = 1; - *r_key = key; - if (secret) - key->secret = 1; - return 0; + *r_key = NULL; + key = xtrycalloc (1, sizeof *key); + if (!key) + return mk_error (Out_Of_Core); + key->ref_count = 1; + *r_key = key; + if (secret) + key->secret = 1; + return 0; } GpgmeError -_gpgme_key_new ( GpgmeKey *r_key ) +_gpgme_key_new (GpgmeKey *r_key) { - return key_new ( r_key, 0 ); + return key_new (r_key, 0); } GpgmeError -_gpgme_key_new_secret ( GpgmeKey *r_key ) +_gpgme_key_new_secret (GpgmeKey *r_key) { - return key_new ( r_key, 1 ); + return key_new (r_key, 1); } @@ -278,48 +333,52 @@ _gpgme_key_new_secret ( GpgmeKey *r_key ) * Use this function to bump the reference counter. **/ void -gpgme_key_ref ( GpgmeKey key ) +gpgme_key_ref (GpgmeKey key) { - return_if_fail (key); - key->ref_count++; + return_if_fail (key); + LOCK (key_ref_lock); + key->ref_count++; + UNLOCK (key_ref_lock); } static struct subkey_s * add_subkey (GpgmeKey key, int secret) { - struct subkey_s *k, *kk; + struct subkey_s *k, *kk; - k = xtrycalloc (1, sizeof *k); - if (!k) - return NULL; + k = xtrycalloc (1, sizeof *k); + if (!k) + return NULL; - if( !(kk=key->keys.next) ) - key->keys.next = k; - else { - while ( kk->next ) - kk = kk->next; - kk->next = k; + if(!(kk = key->keys.next)) + key->keys.next = k; + else + { + while (kk->next) + kk = kk->next; + kk->next = k; } - if (secret) - k->secret = 1; - return k; + if (secret) + k->secret = 1; + return k; } + struct subkey_s * _gpgme_key_add_subkey (GpgmeKey key) { - return add_subkey (key, 0); + return add_subkey (key, 0); } + struct subkey_s * _gpgme_key_add_secret_subkey (GpgmeKey key) { - return add_subkey (key, 1); + return add_subkey (key, 1); } - /** * gpgme_key_release: * @key: Key Object or NULL @@ -330,32 +389,39 @@ _gpgme_key_add_secret_subkey (GpgmeKey key) * as well as for every gpgme_key_ref() done on the key object. **/ void -gpgme_key_release ( GpgmeKey key ) +gpgme_key_release (GpgmeKey key) { - struct user_id_s *u, *u2; - struct subkey_s *k, *k2; + struct user_id_s *u, *u2; + struct subkey_s *k, *k2; - if (!key) - return; + if (!key) + return; - assert (key->ref_count); - if ( --key->ref_count ) - return; - - xfree (key->keys.fingerprint); - for (k = key->keys.next; k; k = k2 ) { - k2 = k->next; - xfree (k->fingerprint); - xfree (k); + LOCK (key_ref_lock); + assert (key->ref_count); + if (--key->ref_count) + { + UNLOCK (key_ref_lock); + return; } - for (u = key->uids; u; u = u2 ) { - u2 = u->next; - xfree (u); + UNLOCK (key_ref_lock); + + xfree (key->keys.fingerprint); + for (k = key->keys.next; k; k = k2) + { + k2 = k->next; + xfree (k->fingerprint); + xfree (k); } - xfree (key->issuer_serial); - xfree (key->issuer_name); - xfree (key->chain_id); - xfree (key); + for (u = key->uids; u; u = u2) + { + u2 = u->next; + xfree (u); + } + xfree (key->issuer_serial); + xfree (key->issuer_name); + xfree (key->chain_id); + xfree (key); } /** @@ -367,111 +433,129 @@ gpgme_key_release ( GpgmeKey key ) void gpgme_key_unref (GpgmeKey key) { - gpgme_key_release (key); + gpgme_key_release (key); } static char * -set_user_id_part ( char *tail, const char *buf, size_t len ) +set_user_id_part (char *tail, const char *buf, size_t len) { - while ( len && (buf[len-1] == ' ' || buf[len-1] == '\t') ) - len--; - for ( ; len; len--) - *tail++ = *buf++; - *tail++ = 0; - return tail; + while (len && (buf[len-1] == ' ' || buf[len-1] == '\t')) + len--; + for (; len; len--) + *tail++ = *buf++; + *tail++ = 0; + return tail; } static void -parse_user_id ( struct user_id_s *uid, char *tail ) +parse_user_id (struct user_id_s *uid, char *tail) { - const char *s, *start=NULL; - int in_name = 0; - int in_email = 0; - int in_comment = 0; + const char *s, *start=NULL; + int in_name = 0; + int in_email = 0; + int in_comment = 0; - 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) { + for (s = uid->name; *s; s++) + { + if (in_email) + { + if (*s == '<') + /* 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 ) { - if ( *s == '(' ) - in_comment++; - else if (*s== ')') { - if ( !--in_comment ) { - if (!uid->comment_part) { + } + } + } + } + else if (in_comment) + { + if (*s == '(') + in_comment++; + 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 ); - } + tail = set_user_id_part (tail, start, s-start); + } in_name = 0; - } + } 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 ); - } + } in_name = 0; - } + } 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 */ + tail = set_user_id_part (tail, start, s-start); + } + } + + /* Let unused parts point to an EOS. */ tail--; if (!uid->name_part) - uid->name_part = tail; + uid->name_part = tail; if (!uid->email_part) - uid->email_part = tail; + uid->email_part = tail; if (!uid->comment_part) - uid->comment_part = tail; - + uid->comment_part = tail; } static void -parse_x509_user_id ( struct user_id_s *uid, char *tail ) +parse_x509_user_id (struct user_id_s *uid, char *tail) { const char *s; s=uid->name; - if (*s == '<' && s[strlen(s)-1] == '>') + 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; @@ -584,64 +668,64 @@ _gpgme_key_append_name (GpgmeKey key, const char *s) static void -add_otag ( GpgmeData d, const char *tag ) +add_otag (GpgmeData d, const char *tag) { - _gpgme_data_append_string ( d, " <" ); - _gpgme_data_append_string ( d, tag ); - _gpgme_data_append_string ( d, ">" ); + _gpgme_data_append_string (d, " <"); + _gpgme_data_append_string (d, tag); + _gpgme_data_append_string (d, ">"); } static void -add_ctag ( GpgmeData d, const char *tag ) +add_ctag (GpgmeData d, const char *tag) { - _gpgme_data_append_string ( d, "\n" ); + _gpgme_data_append_string (d, "\n"); } static void -add_tag_and_string ( GpgmeData d, const char *tag, const char *string ) +add_tag_and_string (GpgmeData d, const char *tag, const char *string) { - add_otag (d, tag); - _gpgme_data_append_string_for_xml ( d, string ); - add_ctag (d, tag); + add_otag (d, tag); + _gpgme_data_append_string_for_xml (d, string); + add_ctag (d, tag); } static void -add_tag_and_uint ( GpgmeData d, const char *tag, unsigned int val ) +add_tag_and_uint (GpgmeData d, const char *tag, unsigned int val) { - char buf[30]; - sprintf (buf, "%u", val ); - add_tag_and_string ( d, tag, buf ); + char buf[30]; + sprintf (buf, "%u", val); + add_tag_and_string (d, tag, buf); } static void -add_tag_and_time ( GpgmeData d, const char *tag, time_t val ) +add_tag_and_time (GpgmeData d, const char *tag, time_t val) { - char buf[30]; + char buf[30]; - if (!val || val == (time_t)-1 ) - return; - sprintf (buf, "%lu", (unsigned long)val ); - add_tag_and_string ( d, tag, buf ); + if (!val || val == (time_t) - 1) + return; + sprintf (buf, "%lu", (unsigned long) val); + add_tag_and_string (d, tag, buf); } static void one_uid_as_xml (GpgmeData d, struct user_id_s *u) { - _gpgme_data_append_string (d, " \n"); - if ( u->invalid ) - _gpgme_data_append_string ( d, " \n"); - if ( u->revoked ) - _gpgme_data_append_string ( d, " \n"); - add_tag_and_string ( d, "raw", u->name ); - if ( *u->name_part ) - add_tag_and_string ( d, "name", u->name_part ); - if ( *u->email_part ) - add_tag_and_string ( d, "email", u->email_part ); - if ( *u->comment_part ) - add_tag_and_string ( d, "comment", u->comment_part ); - _gpgme_data_append_string (d, " \n"); + _gpgme_data_append_string (d, " \n"); + if (u->invalid) + _gpgme_data_append_string (d, " \n"); + if (u->revoked) + _gpgme_data_append_string (d, " \n"); + add_tag_and_string (d, "raw", u->name); + if (*u->name_part) + add_tag_and_string (d, "name", u->name_part); + if (*u->email_part) + add_tag_and_string (d, "email", u->email_part); + if (*u->comment_part) + add_tag_and_string (d, "comment", u->comment_part); + _gpgme_data_append_string (d, " \n"); } @@ -656,37 +740,37 @@ one_uid_as_xml (GpgmeData d, struct user_id_s *u) * a NULL passed as @key **/ char * -gpgme_key_get_as_xml ( GpgmeKey key ) +gpgme_key_get_as_xml (GpgmeKey key) { GpgmeData d; struct user_id_s *u; struct subkey_s *k; - if ( !key ) + if (!key) return NULL; - if ( gpgme_data_new ( &d ) ) + if (gpgme_data_new (&d)) return NULL; - _gpgme_data_append_string ( d, "\n" - " \n" ); - if ( key->keys.secret ) - _gpgme_data_append_string ( d, " \n"); - if ( key->keys.flags.invalid ) - _gpgme_data_append_string ( d, " \n"); - if ( key->keys.flags.revoked ) - _gpgme_data_append_string ( d, " \n"); - if ( key->keys.flags.expired ) - _gpgme_data_append_string ( d, " \n"); - if ( key->keys.flags.disabled ) - _gpgme_data_append_string ( d, " \n"); - add_tag_and_string (d, "keyid", key->keys.keyid ); + _gpgme_data_append_string (d, "\n" + " \n"); + if (key->keys.secret) + _gpgme_data_append_string (d, " \n"); + if (key->keys.flags.invalid) + _gpgme_data_append_string (d, " \n"); + if (key->keys.flags.revoked) + _gpgme_data_append_string (d, " \n"); + if (key->keys.flags.expired) + _gpgme_data_append_string (d, " \n"); + if (key->keys.flags.disabled) + _gpgme_data_append_string (d, " \n"); + add_tag_and_string (d, "keyid", key->keys.keyid); if (key->keys.fingerprint) - add_tag_and_string (d, "fpr", key->keys.fingerprint ); - add_tag_and_uint (d, "algo", key->keys.key_algo ); - add_tag_and_uint (d, "len", key->keys.key_len ); - add_tag_and_time (d, "created", key->keys.timestamp ); - add_tag_and_time (d, "expire", key->keys.expires_at ); + add_tag_and_string (d, "fpr", key->keys.fingerprint); + add_tag_and_uint (d, "algo", key->keys.key_algo); + add_tag_and_uint (d, "len", key->keys.key_len); + add_tag_and_time (d, "created", key->keys.timestamp); + add_tag_and_time (d, "expire", key->keys.expires_at); if (key->issuer_serial) add_tag_and_string (d, "serial", key->issuer_serial); if (key->issuer_name) @@ -694,35 +778,35 @@ gpgme_key_get_as_xml ( GpgmeKey key ) if (key->chain_id) add_tag_and_string (d, "chainid", key->chain_id); _gpgme_data_append_string (d, " \n"); - + /* Now the user IDs. */ for (u = key->uids; u; u = u->next) one_uid_as_xml (d,u); - /* and now the subkeys */ - for (k=key->keys.next; k; k = k->next ) + /* And now the subkeys. */ + for (k = key->keys.next; k; k = k->next) { _gpgme_data_append_string (d, " \n"); - if ( k->secret ) - _gpgme_data_append_string ( d, " \n"); - if ( k->flags.invalid ) - _gpgme_data_append_string ( d, " \n"); - if ( k->flags.revoked ) - _gpgme_data_append_string ( d, " \n"); - if ( k->flags.expired ) - _gpgme_data_append_string ( d, " \n"); - if ( k->flags.disabled ) - _gpgme_data_append_string ( d, " \n"); - add_tag_and_string (d, "keyid", k->keyid ); + if (k->secret) + _gpgme_data_append_string (d, " \n"); + if (k->flags.invalid) + _gpgme_data_append_string (d, " \n"); + if (k->flags.revoked) + _gpgme_data_append_string (d, " \n"); + if (k->flags.expired) + _gpgme_data_append_string (d, " \n"); + if (k->flags.disabled) + _gpgme_data_append_string (d, " \n"); + add_tag_and_string (d, "keyid", k->keyid); if (k->fingerprint) - add_tag_and_string (d, "fpr", k->fingerprint ); - add_tag_and_uint (d, "algo", k->key_algo ); - add_tag_and_uint (d, "len", k->key_len ); - add_tag_and_time (d, "created", k->timestamp ); - add_tag_and_time (d, "expire", k->expires_at ); + add_tag_and_string (d, "fpr", k->fingerprint); + add_tag_and_uint (d, "algo", k->key_algo); + add_tag_and_uint (d, "len", k->key_len); + add_tag_and_time (d, "created", k->timestamp); + add_tag_and_time (d, "expire", k->expires_at); _gpgme_data_append_string (d, " \n"); } - _gpgme_data_append_string ( d, "\n" ); + _gpgme_data_append_string (d, "\n"); return _gpgme_data_release_and_return_string (d); } @@ -731,23 +815,23 @@ gpgme_key_get_as_xml ( GpgmeKey key ) static const char * capabilities_to_string (struct subkey_s *k) { - static char *strings[8] = { - "", - "c", - "s", - "sc", - "e", - "ec", - "es", - "esc" + static const char *const strings[8] = + { + "", + "c", + "s", + "sc", + "e", + "ec", + "es", + "esc" }; - return strings[ (!!k->flags.can_encrypt << 2) - | (!!k->flags.can_sign << 1) - | (!!k->flags.can_certify ) ]; + return strings[(!!k->flags.can_encrypt << 2) + | (!!k->flags.can_sign << 1) + | (!!k->flags.can_certify )]; } - /** * gpgme_key_get_string_attr: * @key: Key Object @@ -764,116 +848,133 @@ capabilities_to_string (struct subkey_s *k) * as the key object itself is valid. **/ const char * -gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what, - const void *reserved, int idx ) +gpgme_key_get_string_attr (GpgmeKey key, GpgmeAttr what, + const void *reserved, int idx) { - const char *val = NULL; - struct subkey_s *k; - struct user_id_s *u; + const char *val = NULL; + struct subkey_s *k; + struct user_id_s *u; - if (!key) - return NULL; - if (reserved) - return NULL; - if (idx < 0) - return NULL; + if (!key) + return NULL; + if (reserved) + return NULL; + if (idx < 0) + return NULL; - switch (what) { - case GPGME_ATTR_KEYID: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->keyid; - break; - case GPGME_ATTR_FPR: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->fingerprint; - break; - case GPGME_ATTR_ALGO: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = pkalgo_to_string (k->key_algo); - break; - case GPGME_ATTR_LEN: - case GPGME_ATTR_CREATED: - case GPGME_ATTR_EXPIRE: - break; /* use another get function */ - case GPGME_ATTR_OTRUST: - val = "[fixme]"; - break; - case GPGME_ATTR_USERID: - for (u=key->uids; u && idx; u=u->next, idx-- ) - ; - val = u? u->name : NULL; - break; - case GPGME_ATTR_NAME: - for (u=key->uids; u && idx; u=u->next, idx-- ) - ; - val = u? u->name_part : NULL; - break; - case GPGME_ATTR_EMAIL: - for (u=key->uids; u && idx; u=u->next, idx-- ) - ; - val = u? u->email_part : NULL; - break; - case GPGME_ATTR_COMMENT: - for (u=key->uids; u && idx; u=u->next, idx-- ) - ; - val = u? u->comment_part : NULL; - break; - 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; + switch (what) + { + case GPGME_ATTR_KEYID: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->keyid; + break; + case GPGME_ATTR_FPR: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->fingerprint; + break; + case GPGME_ATTR_ALGO: + for (k = &key->keys; k && idx; k=k->next, idx--) + ; + if (k) + val = pkalgo_to_string (k->key_algo); + break; + case GPGME_ATTR_LEN: + case GPGME_ATTR_CREATED: + case GPGME_ATTR_EXPIRE: + /* Use another get function. */ + break; + case GPGME_ATTR_OTRUST: + val = "[fixme]"; + break; + case GPGME_ATTR_USERID: + for (u = key->uids; u && idx; u = u->next, idx--) + ; + val = u ? u->name : NULL; + break; + case GPGME_ATTR_NAME: + for (u = key->uids; u && idx; u = u->next, idx--) + ; + val = u ? u->name_part : NULL; + break; + case GPGME_ATTR_EMAIL: + for (u = key->uids; u && idx; u = u->next, idx--) + ; + val = u ? u->email_part : NULL; + break; + case GPGME_ATTR_COMMENT: + for (u = key->uids; u && idx; u = u->next, idx--) + ; + val = u ? u->comment_part : NULL; + break; + 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; } } - break; - case GPGME_ATTR_LEVEL: /* not used here */ - case GPGME_ATTR_TYPE: - case GPGME_ATTR_KEY_REVOKED: - case GPGME_ATTR_KEY_INVALID: - case GPGME_ATTR_KEY_EXPIRED: - case GPGME_ATTR_KEY_DISABLED: - case GPGME_ATTR_UID_REVOKED: - case GPGME_ATTR_UID_INVALID: - case GPGME_ATTR_CAN_ENCRYPT: - case GPGME_ATTR_CAN_SIGN: - case GPGME_ATTR_CAN_CERTIFY: - break; - case GPGME_ATTR_IS_SECRET: - if (key->secret) - val = "1"; - break; - case GPGME_ATTR_KEY_CAPS: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = capabilities_to_string (k); - break; - case GPGME_ATTR_SERIAL: - val = key->issuer_serial; - break; - case GPGME_ATTR_ISSUER: - val = key->issuer_name; - break; - case GPGME_ATTR_CHAINID: - val = key->chain_id; - break; - case GPGME_ATTR_SIG_STATUS: - /* not of any use here */ - break; + break; + case GPGME_ATTR_LEVEL: + case GPGME_ATTR_TYPE: + case GPGME_ATTR_KEY_REVOKED: + case GPGME_ATTR_KEY_INVALID: + case GPGME_ATTR_KEY_EXPIRED: + case GPGME_ATTR_KEY_DISABLED: + case GPGME_ATTR_UID_REVOKED: + case GPGME_ATTR_UID_INVALID: + 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) + val = "1"; + break; + case GPGME_ATTR_KEY_CAPS: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = capabilities_to_string (k); + break; + case GPGME_ATTR_SERIAL: + val = key->issuer_serial; + break; + case GPGME_ATTR_ISSUER: + val = key->issuer_name; + break; + case GPGME_ATTR_CHAINID: + val = key->chain_id; + break; + case GPGME_ATTR_SIG_STATUS: + /* Not of any use here. */ + break; } - return val; + return val; } @@ -894,101 +995,102 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what, * Return value: 0 or the requested value. **/ unsigned long -gpgme_key_get_ulong_attr ( GpgmeKey key, GpgmeAttr what, - const void *reserved, int idx ) +gpgme_key_get_ulong_attr (GpgmeKey key, GpgmeAttr what, + const void *reserved, int idx) { - unsigned long val = 0; - struct subkey_s *k; - struct user_id_s *u; + unsigned long val = 0; + struct subkey_s *k; + struct user_id_s *u; - if (!key) - return 0; - if (reserved) - return 0; - if (idx < 0) - return 0; + if (!key) + return 0; + if (reserved) + return 0; + if (idx < 0) + return 0; - switch (what) { - case GPGME_ATTR_ALGO: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = (unsigned long)k->key_algo; - break; - case GPGME_ATTR_LEN: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = (unsigned long)k->key_len; - break; - case GPGME_ATTR_CREATED: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->timestamp < 0? 0L:(unsigned long)k->timestamp; - break; - case GPGME_ATTR_EXPIRE: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->expires_at < 0? 0L:(unsigned long)k->expires_at; - break; - case GPGME_ATTR_VALIDITY: - for (u=key->uids; u && idx; u=u->next, idx-- ) - ; - if (u) - val = u->validity; - break; - case GPGME_ATTR_IS_SECRET: - val = !!key->secret; - break; - case GPGME_ATTR_KEY_REVOKED: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->flags.revoked; - break; - case GPGME_ATTR_KEY_INVALID: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->flags.invalid; - break; - case GPGME_ATTR_KEY_EXPIRED: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->flags.expired; - break; - case GPGME_ATTR_KEY_DISABLED: - for (k=&key->keys; k && idx; k=k->next, idx-- ) - ; - if (k) - val = k->flags.disabled; - break; - case GPGME_ATTR_UID_REVOKED: - for (u=key->uids; u && idx; u=u->next, idx-- ) - ; - if (u) - val = u->revoked; - break; - case GPGME_ATTR_UID_INVALID: - for (u=key->uids; u && idx; u=u->next, idx-- ) - ; - if (u) - val = u->invalid; - break; - case GPGME_ATTR_CAN_ENCRYPT: - val = key->gloflags.can_encrypt; - break; - case GPGME_ATTR_CAN_SIGN: - val = key->gloflags.can_sign; - break; - case GPGME_ATTR_CAN_CERTIFY: - val = key->gloflags.can_certify; - break; - default: - break; + switch (what) + { + case GPGME_ATTR_ALGO: + for (k = &key->keys; k && idx; k=k->next, idx--) + ; + if (k) + val = (unsigned long) k->key_algo; + break; + case GPGME_ATTR_LEN: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = (unsigned long) k->key_len; + break; + case GPGME_ATTR_CREATED: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->timestamp < 0 ? 0L : (unsigned long) k->timestamp; + break; + case GPGME_ATTR_EXPIRE: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->expires_at < 0 ? 0L : (unsigned long) k->expires_at; + break; + case GPGME_ATTR_VALIDITY: + for (u = key->uids; u && idx; u = u->next, idx--) + ; + if (u) + val = u->validity; + break; + case GPGME_ATTR_IS_SECRET: + val = !!key->secret; + break; + case GPGME_ATTR_KEY_REVOKED: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->flags.revoked; + break; + case GPGME_ATTR_KEY_INVALID: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->flags.invalid; + break; + case GPGME_ATTR_KEY_EXPIRED: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->flags.expired; + break; + case GPGME_ATTR_KEY_DISABLED: + for (k = &key->keys; k && idx; k = k->next, idx--) + ; + if (k) + val = k->flags.disabled; + break; + case GPGME_ATTR_UID_REVOKED: + for (u = key->uids; u && idx; u = u->next, idx--) + ; + if (u) + val = u->revoked; + break; + case GPGME_ATTR_UID_INVALID: + for (u = key->uids; u && idx; u = u->next, idx--) + ; + if (u) + val = u->invalid; + break; + case GPGME_ATTR_CAN_ENCRYPT: + val = key->gloflags.can_encrypt; + break; + case GPGME_ATTR_CAN_SIGN: + val = key->gloflags.can_sign; + break; + case GPGME_ATTR_CAN_CERTIFY: + val = key->gloflags.can_certify; + break; + default: + break; } - return val; + return val; } diff --git a/gpgme/posix-io.c b/gpgme/posix-io.c index be418d2a..fbfbd223 100644 --- a/gpgme/posix-io.c +++ b/gpgme/posix-io.c @@ -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; @@ -314,7 +317,7 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds) } else if (fds[i].for_write) { - assert (!FD_ISSET ( fds[i].fd, &writefds)); + assert (!FD_ISSET (fds[i].fd, &writefds)); FD_SET (fds[i].fd, &writefds); if (fds[i].fd > max_fd) max_fd = fds[i].fd; diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 668ed267..1d6aa2b1 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -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; } diff --git a/gpgme/version.c b/gpgme/version.c index 104f71d7..2b2874b2 100644 --- a/gpgme/version.c +++ b/gpgme/version.c @@ -43,6 +43,7 @@ do_subsystem_inits (void) return; _gpgme_sema_subsystem_init (); _gpgme_key_cache_init (); + done = 1; } static const char* @@ -148,45 +149,50 @@ const char * gpgme_get_engine_info () { static const char *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; + DEFINE_STATIC_LOCK (engine_info_lock); - /* FIXME: Make sure that only one instance does run. */ - if (engine_info) - return engine_info; - - if (!openpgp_info && !cms_info) - info = "\n\n"; - else if (!openpgp_info || !cms_info) + LOCK (engine_info_lock); + if (!engine_info) { - const char *fmt = "\n" - "%s" - "\n"; + const char *openpgp_info = _gpgme_engine_get_info (GPGME_PROTOCOL_OpenPGP); + const char *cms_info = _gpgme_engine_get_info (GPGME_PROTOCOL_CMS); + char *info; - info = xtrymalloc (strlen(fmt) + strlen(openpgp_info - ? openpgp_info : cms_info) + 1); - if (info) - sprintf (info, fmt, openpgp_info ? openpgp_info : cms_info); + if (!openpgp_info && !cms_info) + info = "\n\n"; + else if (!openpgp_info || !cms_info) + { + const char *fmt = "\n" + "%s" + "\n"; + + info = xtrymalloc (strlen (fmt) + + strlen (openpgp_info + ? openpgp_info : cms_info) + 1); + if (info) + sprintf (info, fmt, openpgp_info ? openpgp_info : cms_info); + } + else + { + const char *fmt = "\n" + "%s%s" + "\n"; + info = xtrymalloc (strlen (fmt) + strlen (openpgp_info) + + strlen (cms_info) + 1); + if (info) + sprintf (info, fmt, openpgp_info, cms_info); + } + if (!info) + info = "\n" + " Out of core\n" + "\n"; + engine_info = info; } - else - { - const char *fmt = "\n" - "%s%s" - "\n"; - info = xtrymalloc (strlen(fmt) + strlen(openpgp_info) - + strlen (cms_info) + 1); - if (info) - sprintf (info, fmt, openpgp_info, cms_info); - } - if (!info) - info = "\n" - " Out of core\n" - "\n"; - engine_info = info; + UNLOCK (engine_info_lock); return engine_info; } + /** * gpgme_check_engine: * diff --git a/gpgme/w32-util.c b/gpgme/w32-util.c index c6e19319..a0a42240 100644 --- a/gpgme/w32-util.c +++ b/gpgme/w32-util.c @@ -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; }