g10: Eliminate the redundant function get_keyblock_byfprint.
[gnupg.git] / agent / cache.c
index 9c20469..49402e4 100644 (file)
@@ -24,7 +24,7 @@
 #include <string.h>
 #include <time.h>
 #include <assert.h>
-#include <pth.h>
+#include <npth.h>
 
 #include "agent.h"
 
@@ -33,7 +33,7 @@
 
 /* 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
@@ -65,17 +65,21 @@ struct cache_item_s {
 /* 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));
 }
 
 
@@ -98,12 +102,14 @@ init_encryption (void)
 {
   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);
@@ -127,8 +133,9 @@ init_encryption (void)
     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;
 }
@@ -148,6 +155,7 @@ new_data (const char *string, struct secret_data_s **r_data)
   struct secret_data_s *d, *d_enc;
   size_t length;
   int total;
+  int res;
 
   *r_data = NULL;
 
@@ -178,13 +186,17 @@ new_data (const char *string, struct secret_data_s **r_data)
     }
 
   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);
@@ -209,7 +221,7 @@ housekeeping (void)
       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;
@@ -231,7 +243,7 @@ housekeeping (void)
       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;
@@ -247,7 +259,7 @@ housekeeping (void)
         {
           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)
@@ -278,7 +290,7 @@ agent_flush_cache (void)
       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;
@@ -302,7 +314,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
   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 ();
 
@@ -378,12 +390,25 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
   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)
@@ -394,6 +419,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
               || 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");
@@ -405,19 +431,23 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
             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;
@@ -428,3 +458,14 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
 
   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;
+}