* gpg-agent.c (main): Disable core dumps.
authorWerner Koch <wk@gnupg.org>
Sat, 19 Jan 2002 20:59:19 +0000 (20:59 +0000)
committerWerner Koch <wk@gnupg.org>
Sat, 19 Jan 2002 20:59:19 +0000 (20:59 +0000)
* cache.c: New.
* command.c (cmd_get_passphrase): Use the cache.
(cmd_clear_passphrase): Ditto.

* gpg-agent.c:  Removed unused cruft and implement the socket
based server.
(my_strusage): Take bug report address from configure.ac.
* command.c (start_command_handler): Add an argument to start as
regular server.
(start_command_handler): Enable Assuan logging.

agent/ChangeLog
agent/Makefile.am
agent/agent.h
agent/cache.c [new file with mode: 0644]
agent/command.c
agent/gpg-agent.c

index 95285c3..536aed8 100644 (file)
@@ -1,5 +1,11 @@
 2002-01-19  Werner Koch  <wk@gnupg.org>
 
+       * gpg-agent.c (main): Disable core dumps.
+
+       * cache.c: New.
+       * command.c (cmd_get_passphrase): Use the cache.
+       (cmd_clear_passphrase): Ditto.
+
        * gpg-agent.c:  Removed unused cruft and implement the socket
        based server.
        (my_strusage): Take bug report address from configure.ac.
index 68ee4c7..013862e 100644 (file)
@@ -27,6 +27,7 @@ gpg_agent_SOURCES = \
        gpg-agent.c agent.h \
        command.c \
        query.c \
+       cache.c \
        trans.c \
        findkey.c \
        pksign.c \
index ad0a6e8..ca70150 100644 (file)
@@ -100,6 +100,12 @@ int agent_get_passphrase (char **retpass,
                           const char *desc, const char *prompt,
                           const char *errtext);
 
+/*-- cache.c --*/
+int agent_put_cache (const char *key, const char *data, int ttl);
+const char *agent_get_cache (const char *key);
+
+
+
 /*-- pksign.c --*/
 int agent_pksign (CTRL ctrl, FILE *outfp);
 
diff --git a/agent/cache.c b/agent/cache.c
new file mode 100644 (file)
index 0000000..9621371
--- /dev/null
@@ -0,0 +1,220 @@
+/* cache.c - keep a cache of passphrases
+ *     Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+
+#include "agent.h"
+
+struct secret_data_s {
+  int  totallen; /* this includes the padding */
+  int  datalen;  /* actual data length */
+  char data[1];
+};
+
+typedef struct cache_item_s *ITEM;
+struct cache_item_s {
+  ITEM next;
+  time_t created;
+  time_t accessed;
+  int  ttl;  /* max. lifetime given in seonds */
+  struct secret_data_s *pw;
+  char key[1];
+};
+
+
+static ITEM thecache;
+
+
+static void
+release_data (struct secret_data_s *data)
+{
+   xfree (data);
+}
+
+static struct secret_data_s *
+new_data (const void *data, size_t length)
+{
+  struct secret_data_s *d;
+  int total;
+
+  /* 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 storage provider*/
+  total = length + 32 - (length % 32);
+
+  d = gcry_malloc_secure (sizeof d + total - 1);
+  if (d)
+    {
+      d->totallen = total;
+      d->datalen  = length;
+      memcpy (d->data, data, length);
+    }
+  return d;
+}
+
+
+/* check whether there are items to expire */
+static void
+housekeeping (void)
+{
+  ITEM r, rprev;
+  time_t current = time (NULL);
+
+  /* first expire the actual data */
+  for (r=thecache; r; r = r->next)
+    {
+      if (r->pw && r->accessed + r->ttl < current)
+        {
+          release_data (r->pw);
+          r->pw = NULL;
+          r->accessed = current;
+        }
+    }
+
+  /* second, make sure that we also remove them based on the created stamp so
+     that the used has to enter it from time to time.  We do this every hour */
+  for (r=thecache; r; r = r->next)
+    {
+      if (r->pw && r->created + 60*60 < current)
+        {
+          release_data (r->pw);
+          r->pw = NULL;
+          r->accessed = current;
+        }
+    }
+
+  /* third, make sure that we don't have too many items in the list.
+     Expire old and unused entries after 30 minutes */
+  for (rprev=NULL, r=thecache; r; )
+    {
+      if (!r->pw && r->accessed + 60*30 < current)
+        {
+          ITEM r2 = r->next;
+          xfree (r);
+          if (!rprev)
+            thecache = r2;
+          else
+            rprev = r2;
+          r = r2;
+        }
+      else
+        {
+          rprev = r;
+          r = r->next;
+        }
+    }
+}
+
+
+
+/* Store DATA of length DATALEN in the cache under KEY and mark it
+   with a maxiumum lifetime of TTL seconds.  If tehre is already data
+   under this key, it will be replaced.  Using a DATA of NULL deletes
+   the entry */
+int
+agent_put_cache (const char *key, const char *data, int ttl)
+{
+  ITEM r;
+
+  housekeeping ();
+
+  if (ttl < 1)
+    ttl = 60*5; /* default is 5 minutes */
+
+  for (r=thecache; r; r = r->next)
+    {
+      if ( !strcmp (r->key, key))
+        break;
+    }
+  if (r)
+    { /* replace */
+      if (r->pw)
+        {
+          release_data (r->pw);
+          r->pw = NULL;
+        }
+      if (data)
+        {
+          r->pw = new_data (data, strlen (data)+1);
+          if (!r->pw)
+            log_error ("out of core while allocating new cache item\n");
+        }
+    }
+  else if (data)
+    { /* simply insert */
+      r = xtrycalloc (1, sizeof *r + strlen (key));
+      if (!r)
+        log_error ("out of core while allocating new cache control\n");
+      else
+        {
+          strcpy (r->key, key);
+          r->created = r->accessed = time (NULL); 
+          r->ttl = ttl;
+          r->pw = new_data (data, strlen (data)+1);
+          if (!r->pw)
+            {
+              log_error ("out of core while allocating new cache item\n");
+              xfree (r);
+            }
+          else
+            {
+              r->next = thecache;
+              thecache = r;
+            }
+        }
+    }
+  return 0;
+}
+
+
+/* Try to find an item in the cache */
+const char *
+agent_get_cache (const char *key)
+{
+  ITEM r;
+  int count = 0;
+
+  housekeeping ();
+
+  /* FIXME: Returning pointers is not thread safe - add a referencense
+     counter */
+  for (r=thecache; r; r = r->next, count++)
+    {
+      if (r->pw && !strcmp (r->key, key))
+        {
+          /* put_cache does onlu put strings into the cache, so we
+             don't need the lengths */
+          r->accessed = time (NULL);
+          return r->pw->data;
+        }
+    }
+
+  return NULL;
+}
+
+
+
index bde3835..dae6c34 100644 (file)
@@ -281,20 +281,74 @@ static int
 cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
 {
   int rc;
+  const char *pw;
   char *response;
-  char *desc, *prompt, *errtext;
-
-  /* FIXME: Parse that stuff */
-  desc = "We need a passphrase";
-  prompt = NULL;
-  errtext = NULL;
+  char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
+  char *p;
 
-  rc = agent_get_passphrase (&response, desc, prompt, errtext);
-  if (!rc)
+  /* parse the stuff */
+  for (p=line; *p == ' '; p++)
+    ;
+  cacheid = p;
+  p = strchr (cacheid, ' ');
+  if (p)
+    {
+      *p++ = 0;
+      while (*p == ' ')
+        p++;
+      errtext = p;
+      p = strchr (errtext, ' ');
+      if (p)
+        {
+          *p++ = 0;
+          while (*p == ' ')
+            p++;
+          prompt = p;
+          p = strchr (prompt, ' ');
+          if (p)
+            {
+              *p++ = 0;
+              while (*p == ' ')
+                p++;
+              desc = p;
+              p = strchr (desc, ' ');
+              if (p)
+                *p = 0; /* ignore garbage */
+            }
+        }
+    }
+  if (!cacheid || !*cacheid || strlen (cacheid) > 50)
+    return set_error (Parameter_Error, "invalid length of cacheID");
+  if (!desc)
+    return set_error (Parameter_Error, "no description given");
+
+  if (!strcmp (cacheid, "X"))
+    cacheid = NULL;
+  if (!strcmp (errtext, "X"))
+    errtext = NULL;
+  if (!strcmp (prompt, "X"))
+    prompt = NULL;
+  if (!strcmp (desc, "X"))
+    desc = NULL;
+
+  /* Note: we store the hexified versions in the cache. */
+  pw = cacheid ? agent_get_cache (cacheid) : NULL;
+  if (pw)
     {
       assuan_begin_confidential (ctx);
-      rc = assuan_set_okay_line (ctx, response);
-      xfree (response);
+      rc = assuan_set_okay_line (ctx, pw);
+    }
+  else
+    {
+      rc = agent_get_passphrase (&response, desc, prompt, errtext);
+      if (!rc)
+        {
+          if (cacheid)
+            agent_put_cache (cacheid, response, 0);
+          assuan_begin_confidential (ctx);
+          rc = assuan_set_okay_line (ctx, response);
+          xfree (response);
+        }
     }
 
   return map_to_assuan_status (rc);
@@ -310,12 +364,21 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
 static int
 cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
 {
-  int rc;
-
-  /* fixme: no caching yet. so return with OK */
-  rc = 0;
+  char *cacheid = NULL;
+  char *p;
 
-  return map_to_assuan_status (rc);
+  /* parse the stuff */
+  for (p=line; *p == ' '; p++)
+    ;
+  cacheid = p;
+  p = strchr (cacheid, ' ');
+  if (p)
+    *p = 0; /* ignore garbage */
+  if (!cacheid || !*cacheid || strlen (cacheid) > 50)
+    return set_error (Parameter_Error, "invalid length of cacheID");
+
+  agent_put_cache (cacheid, NULL, 0);
+  return 0;
 }
 
 
index 6dca963..1c3efee 100644 (file)
@@ -40,6 +40,8 @@
 #include "agent.h"
 #include "../assuan/assuan.h" /* malloc hooks */
 
+#include "sysutils.h"
+
 
 #define N_(a) a
 #define _(a) a
@@ -252,7 +254,7 @@ main (int argc, char **argv )
   gcry_set_log_handler (my_gcry_logger, NULL);
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
 
-  may_coredump = 0/* FIXME: disable_core_dumps()*/;
+  may_coredump = disable_core_dumps ();
 
   shell = getenv ("SHELL");
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )