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