aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcus Brinkmann <[email protected]>2002-05-09 03:38:12 +0000
committerMarcus Brinkmann <[email protected]>2002-05-09 03:38:12 +0000
commit4e0d4d7cf3e630fbde187c506799048a3f359fc1 (patch)
treeea81a03cf56216cd56be94605e474aff0f5de05c
parentrevoce the previous commit, this was done erroneously (diff)
downloadgpgme-4e0d4d7cf3e630fbde187c506799048a3f359fc1.tar.gz
gpgme-4e0d4d7cf3e630fbde187c506799048a3f359fc1.zip
doc/
2002-05-09 Marcus Brinkmann <[email protected]> * gpgme.texi (Overview): Replace note about thread-safeness. (Multi Threading): New section. gpgme/ 2002-05-08 Marcus Brinkmann <[email protected]> * 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.
-rw-r--r--TODO3
-rw-r--r--doc/ChangeLog5
-rw-r--r--doc/gpgme.texi85
-rw-r--r--gpgme/ChangeLog32
-rw-r--r--gpgme/engine-gpgsm.c5
-rw-r--r--gpgme/engine.c55
-rw-r--r--gpgme/gpgme.h2
-rw-r--r--gpgme/import.c8
-rw-r--r--gpgme/key.c1220
-rw-r--r--gpgme/posix-io.c13
-rw-r--r--gpgme/rungpg.c5
-rw-r--r--gpgme/version.c70
-rw-r--r--gpgme/w32-util.c14
13 files changed, 878 insertions, 639 deletions
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 <[email protected]>
+
+ * gpgme.texi (Overview): Replace note about thread-safeness.
+ (Multi Threading): New section.
+
2002-05-03 Werner Koch <[email protected]>
* 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 <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
diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog
index 200dfea0..0696272e 100644
--- a/gpgme/ChangeLog
+++ b/gpgme/ChangeLog
@@ -1,5 +1,37 @@
2002-05-08 Marcus Brinkmann <[email protected]>
+ * 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 <[email protected]>
+
* debug.h: New file.
* Makefile.am (libgpgme_la_SOURCES): Add debug.h.
* util.h: Removed all prototypes and declarations related to
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)
" </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];
-
- 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 = " <engine>\n"
- " <error>Out of core</error>\n"
- " </engine>";
- 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 = " <engine>\n"
+ " <error>Out of core</error>\n"
+ " </engine>";
+ 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;
+/* 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 )
+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;
+ 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;
+ 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;
+ 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;
-
- 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 ) {
- 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;
+ struct subkey_s *k;
+
+ if (!key)
+ return;
+
+ _gpgme_key_cache_init ();
+
+ 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 (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;
+ 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;
+ 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 */
+ 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;
+
+ 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;
-
- *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;
+ 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;
}
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;
-
- 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;
+ struct subkey_s *k, *kk;
+
+ 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 (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;
+ 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 ) {
- k2 = k->next;
- xfree (k->fingerprint);
- xfree (k);
+ xfree (key->keys.fingerprint);
+ for (k = key->keys.next; k; k = k2)
+ {
+ k2 = k->next;
+ xfree (k->fingerprint);
+ xfree (k);
}
- for (u = key->uids; u; u = u2 ) {
- u2 = u->next;
- xfree (u);
+ 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);
+ 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;
-
- 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) {
+ 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 == '<')
+ /* 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, "</" );
- _gpgme_data_append_string ( d, tag );
- _gpgme_data_append_string ( d, ">\n" );
+ _gpgme_data_append_string (d, "</");
+ _gpgme_data_append_string (d, tag);
+ _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, " <userid>\n");
- if ( u->invalid )
- _gpgme_data_append_string ( d, " <invalid/>\n");
- if ( u->revoked )
- _gpgme_data_append_string ( d, " <revoked/>\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, " </userid>\n");
+ _gpgme_data_append_string (d, " <userid>\n");
+ if (u->invalid)
+ _gpgme_data_append_string (d, " <invalid/>\n");
+ if (u->revoked)
+ _gpgme_data_append_string (d, " <revoked/>\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, " </userid>\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, "<GnupgKeyblock>\n"
- " <mainkey>\n" );
- if ( key->keys.secret )
- _gpgme_data_append_string ( d, " <secret/>\n");
- if ( key->keys.flags.invalid )
- _gpgme_data_append_string ( d, " <invalid/>\n");
- if ( key->keys.flags.revoked )
- _gpgme_data_append_string ( d, " <revoked/>\n");
- if ( key->keys.flags.expired )
- _gpgme_data_append_string ( d, " <expired/>\n");
- if ( key->keys.flags.disabled )
- _gpgme_data_append_string ( d, " <disabled/>\n");
- add_tag_and_string (d, "keyid", key->keys.keyid );
+ _gpgme_data_append_string (d, "<GnupgKeyblock>\n"
+ " <mainkey>\n");
+ if (key->keys.secret)
+ _gpgme_data_append_string (d, " <secret/>\n");
+ if (key->keys.flags.invalid)
+ _gpgme_data_append_string (d, " <invalid/>\n");
+ if (key->keys.flags.revoked)
+ _gpgme_data_append_string (d, " <revoked/>\n");
+ if (key->keys.flags.expired)
+ _gpgme_data_append_string (d, " <expired/>\n");
+ if (key->keys.flags.disabled)
+ _gpgme_data_append_string (d, " <disabled/>\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, " </mainkey>\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, " <subkey>\n");
- if ( k->secret )
- _gpgme_data_append_string ( d, " <secret/>\n");
- if ( k->flags.invalid )
- _gpgme_data_append_string ( d, " <invalid/>\n");
- if ( k->flags.revoked )
- _gpgme_data_append_string ( d, " <revoked/>\n");
- if ( k->flags.expired )
- _gpgme_data_append_string ( d, " <expired/>\n");
- if ( k->flags.disabled )
- _gpgme_data_append_string ( d, " <disabled/>\n");
- add_tag_and_string (d, "keyid", k->keyid );
+ if (k->secret)
+ _gpgme_data_append_string (d, " <secret/>\n");
+ if (k->flags.invalid)
+ _gpgme_data_append_string (d, " <invalid/>\n");
+ if (k->flags.revoked)
+ _gpgme_data_append_string (d, " <revoked/>\n");
+ if (k->flags.expired)
+ _gpgme_data_append_string (d, " <expired/>\n");
+ if (k->flags.disabled)
+ _gpgme_data_append_string (d, " <disabled/>\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, " </subkey>\n");
}
- _gpgme_data_append_string ( d, "</GnupgKeyblock>\n" );
+ _gpgme_data_append_string (d, "</GnupgKeyblock>\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;
-
- 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;
+ 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;
+
+ 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;
-
- 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;
+ 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;
+
+ 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 = "<EngineInfo>\n</EngineInfo>\n";
- else if (!openpgp_info || !cms_info)
+ LOCK (engine_info_lock);
+ if (!engine_info)
{
- const char *fmt = "<EngineInfo>\n"
- "%s"
- "</EngineInfo>\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);
- }
- else
- {
- const char *fmt = "<EngineInfo>\n"
- "%s%s"
- "</EngineInfo>\n";
- info = xtrymalloc (strlen(fmt) + strlen(openpgp_info)
- + strlen (cms_info) + 1);
- if (info)
- sprintf (info, fmt, openpgp_info, cms_info);
+ if (!openpgp_info && !cms_info)
+ info = "<EngineInfo>\n</EngineInfo>\n";
+ else if (!openpgp_info || !cms_info)
+ {
+ const char *fmt = "<EngineInfo>\n"
+ "%s"
+ "</EngineInfo>\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 = "<EngineInfo>\n"
+ "%s%s"
+ "</EngineInfo>\n";
+ info = xtrymalloc (strlen (fmt) + strlen (openpgp_info)
+ + strlen (cms_info) + 1);
+ if (info)
+ sprintf (info, fmt, openpgp_info, cms_info);
+ }
+ if (!info)
+ info = "<EngineInfo>\n"
+ " <error>Out of core</error>\n"
+ "</EngineInfo>\n";
+ engine_info = info;
}
- if (!info)
- info = "<EngineInfo>\n"
- " <error>Out of core</error>\n"
- "</EngineInfo>\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;
}