Implement /run/user/UID/gnupg based sockets.
[gnupg.git] / agent / cache.c
index 9b90d93..3fffd2d 100644 (file)
@@ -65,6 +65,9 @@ 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.  */
@@ -164,7 +167,7 @@ new_data (const char *string, struct secret_data_s **r_data)
 
   /* We pad the data to 32 bytes so that it get more complicated
      finding something out by watching allocation patterns.  This is
-     usally not possible but we better assume nothing about our secure
+     usually not possible but we better assume nothing about our secure
      storage provider.  To support the AESWRAP mode we need to add 8
      extra bytes as well. */
   total = (length + 8) + 32 - ((length+8) % 32);
@@ -218,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;
@@ -240,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;
@@ -256,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)
@@ -287,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;
@@ -311,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 ();
 
@@ -388,12 +391,24 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
   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)
@@ -404,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");
@@ -431,7 +447,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
             {
               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;
@@ -442,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;
+}