#include <string.h>
#include <time.h>
#include <assert.h>
-#include <pth.h>
+#include <npth.h>
#include "agent.h"
/* A mutex used to protect the encryption. This is required because
we use one context to do all encryption and decryption. */
-static pth_mutex_t encryption_lock;
+static npth_mutex_t encryption_lock;
/* The encryption context. This is the only place where the
encryption key for all cached entries is available. It would be nice
to keep this (or just the key) in some hardware device, for example
/* The cache himself. */
static ITEM thecache;
+/* NULL or the last cache key stored by agent_store_cache_hit. */
+static char *last_stored_cache_key;
+
/* This function must be called once to initialize this module. It
has to be done before a second thread is spawned. */
void
initialize_module_cache (void)
{
- if (!pth_mutex_init (&encryption_lock))
- {
- gpg_error_t err = gpg_error_from_syserror ();
- log_fatal ("error initializing cache module: %s\n", gpg_strerror (err));
- }
+ int err;
+
+ err = npth_mutex_init (&encryption_lock, NULL);
+
+ if (err)
+ log_fatal ("error initializing cache module: %s\n", strerror (err));
}
{
gpg_error_t err;
void *key;
+ int res;
if (encryption_handle)
return 0; /* Shortcut - Already initialized. */
- if (!pth_mutex_acquire (&encryption_lock, 0, NULL))
- log_fatal ("failed to acquire cache encryption mutex\n");
+ res = npth_mutex_lock (&encryption_lock);
+ if (res)
+ log_fatal ("failed to acquire cache encryption mutex: %s\n", strerror (res));
err = gcry_cipher_open (&encryption_handle, GCRY_CIPHER_AES128,
GCRY_CIPHER_MODE_AESWRAP, GCRY_CIPHER_SECURE);
log_error ("error initializing cache encryption context: %s\n",
gpg_strerror (err));
- if (!pth_mutex_release (&encryption_lock))
- log_fatal ("failed to release cache encryption mutex\n");
+ res = npth_mutex_unlock (&encryption_lock);
+ if (res)
+ log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res));
return err? gpg_error (GPG_ERR_NOT_INITIALIZED) : 0;
}
struct secret_data_s *d, *d_enc;
size_t length;
int total;
+ int res;
*r_data = NULL;
}
d_enc->totallen = total;
- if (!pth_mutex_acquire (&encryption_lock, 0, NULL))
- log_fatal ("failed to acquire cache encryption mutex\n");
+ res = npth_mutex_lock (&encryption_lock);
+ if (res)
+ log_fatal ("failed to acquire cache encryption mutex: %s\n",
+ strerror (res));
+
err = gcry_cipher_encrypt (encryption_handle, d_enc->data, total,
d->data, total - 8);
xfree (d);
- if (!pth_mutex_release (&encryption_lock))
- log_fatal ("failed to release cache encryption mutex\n");
+ res = npth_mutex_unlock (&encryption_lock);
+ if (res)
+ log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res));
if (err)
{
xfree (d_enc);
if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
{
if (DBG_CACHE)
- log_debug (" expired `%s' (%ds after last access)\n",
+ log_debug (" expired '%s' (%ds after last access)\n",
r->key, r->ttl);
release_data (r->pw);
r->pw = NULL;
if (r->pw && r->created + maxttl < current)
{
if (DBG_CACHE)
- log_debug (" expired `%s' (%lus after creation)\n",
+ log_debug (" expired '%s' (%lus after creation)\n",
r->key, opt.max_cache_ttl);
release_data (r->pw);
r->pw = NULL;
{
ITEM r2 = r->next;
if (DBG_CACHE)
- log_debug (" removed `%s' (mode %d) (slot not used for 30m)\n",
+ log_debug (" removed '%s' (mode %d) (slot not used for 30m)\n",
r->key, r->cache_mode);
xfree (r);
if (!rprev)
if (r->pw)
{
if (DBG_CACHE)
- log_debug (" flushing `%s'\n", r->key);
+ log_debug (" flushing '%s'\n", r->key);
release_data (r->pw);
r->pw = NULL;
r->accessed = 0;
ITEM r;
if (DBG_CACHE)
- log_debug ("agent_put_cache `%s' (mode %d) requested ttl=%d\n",
+ log_debug ("agent_put_cache '%s' (mode %d) requested ttl=%d\n",
key, cache_mode, ttl);
housekeeping ();
gpg_error_t err;
ITEM r;
char *value = NULL;
+ int res;
+ int last_stored = 0;
if (cache_mode == CACHE_MODE_IGNORE)
return NULL;
+ if (!key)
+ {
+ key = last_stored_cache_key;
+ if (!key)
+ return NULL;
+ last_stored = 1;
+ }
+
+
if (DBG_CACHE)
- log_debug ("agent_get_cache `%s' (mode %d) ...\n", key, cache_mode);
+ log_debug ("agent_get_cache '%s' (mode %d)%s ...\n",
+ key, cache_mode,
+ last_stored? " (stored cache key)":"");
housekeeping ();
for (r=thecache; r; r = r->next)
|| r->cache_mode == cache_mode)
&& !strcmp (r->key, key))
{
+ /* Note: To avoid races KEY may not be accessed anymore below. */
r->accessed = gnupg_get_time ();
if (DBG_CACHE)
log_debug ("... hit\n");
err = gpg_error_from_syserror ();
else
{
- if (!pth_mutex_acquire (&encryption_lock, 0, NULL))
- log_fatal ("failed to acquire cache encryption mutex\n");
+ res = npth_mutex_lock (&encryption_lock);
+ if (res)
+ log_fatal ("failed to acquire cache encryption mutex: %s\n",
+ strerror (res));
err = gcry_cipher_decrypt (encryption_handle,
value, r->pw->totallen - 8,
r->pw->data, r->pw->totallen);
- if (!pth_mutex_release (&encryption_lock))
- log_fatal ("failed to release cache encryption mutex\n");
+ res = npth_mutex_unlock (&encryption_lock);
+ if (res)
+ log_fatal ("failed to release cache encryption mutex: %s\n",
+ strerror (res));
}
if (err)
{
xfree (value);
value = NULL;
- log_error ("retrieving cache entry `%s' failed: %s\n",
+ log_error ("retrieving cache entry '%s' failed: %s\n",
key, gpg_strerror (err));
}
return value;
return NULL;
}
+
+
+/* Store the key for the last successful cache hit. That value is
+ used by agent_get_cache if the requested KEY is given as NULL.
+ NULL may be used to remove that key. */
+void
+agent_store_cache_hit (const char *key)
+{
+ xfree (last_stored_cache_key);
+ last_stored_cache_key = key? xtrystrdup (key) : NULL;
+}