Friedman is setting up his desk
authorWerner Koch <wk@gnupg.org>
Sat, 24 Nov 2001 18:52:02 +0000 (18:52 +0000)
committerWerner Koch <wk@gnupg.org>
Sat, 24 Nov 2001 18:52:02 +0000 (18:52 +0000)
agent/Makefile.am
agent/agent.h [new file with mode: 0644]
agent/command.c [new file with mode: 0644]
agent/gpg-agent.c
agent/pksign.c [new file with mode: 0644]

index 222a68b..f4b6bf8 100644 (file)
@@ -24,7 +24,9 @@ INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/intl
 LDFLAGS = @LDFLAGS@ 
 
 gpg_agent_SOURCES = \
-       gpg-agent.c
+       gpg-agent.c agent.h \
+       command.c \
+       pksign.c 
 
 gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a  \
               ../../libgcrypt/src/.libs/libgcrypt.so.1 
diff --git a/agent/agent.h b/agent/agent.h
new file mode 100644 (file)
index 0000000..e689b8e
--- /dev/null
@@ -0,0 +1,78 @@
+/* agent.h - Global definitions for the agent
+ *     Copyright (C) 2001 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
+ */
+
+#ifndef AGENT_H
+#define AGENT_H
+
+#include "../common/util.h"
+#include "../common/errors.h"
+
+#define MAX_DIGEST_LEN 24 
+
+/* A large struct name "opt" to keep global flags */
+struct {
+  unsigned int debug; /* debug flags (DBG_foo_VALUE) */
+  int verbose;      /* verbosity level */
+  int quiet;        /* be as quiet as possible */
+  int dry_run;      /* don't change any persistent data */
+  const char *homedir; /* configuration directory name */
+} opt;
+
+
+#define DBG_COMMAND_VALUE 1    /* debug commands i/o */
+#define DBG_MPI_VALUE    2     /* debug mpi details */
+#define DBG_CRYPTO_VALUE  4    /* debug low level crypto */
+#define DBG_MEMORY_VALUE  32   /* debug memory allocation stuff */
+#define DBG_CACHE_VALUE   64   /* debug the caching */
+#define DBG_MEMSTAT_VALUE 128  /* show memory statistics */
+#define DBG_HASHING_VALUE 512  /* debug hashing operations */
+
+#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
+#define DBG_CRYPTO  (opt.debug & DBG_CRYPTO_VALUE)
+#define DBG_MEMORY  (opt.debug & DBG_MEMORY_VALUE)
+#define DBG_CACHE   (opt.debug & DBG_CACHE_VALUE)
+#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
+
+struct server_local_s;
+
+struct server_control_s {
+  struct server_local_s *server_local;
+  struct {
+    unsigned char value[MAX_DIGEST_LEN];
+    int valuelen;
+  } digest;
+
+
+};
+typedef struct server_control_s *CTRL;
+
+/*-- gpg-agent.c --*/
+void agent_exit (int rc);
+
+
+/*-- command.c --*/
+void start_command_handler (void);
+
+/*-- pksign.c --*/
+int agent_pksign (CTRL ctrl, FILE *outfp);
+
+
+
+#endif /*AGENT_H*/
diff --git a/agent/command.c b/agent/command.c
new file mode 100644 (file)
index 0000000..62950b3
--- /dev/null
@@ -0,0 +1,229 @@
+/* command.c - gpg-agent command handler
+ *     Copyright (C) 2001 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
+ */
+
+/* FIXME: we should not use the default assuan buffering but setup
+   some buffering in secure mempory to protect session keys etc. */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "agent.h"
+#include "../assuan/assuan.h"
+
+#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
+#define digitp(a) ((a) >= '0' && (a) <= '9')
+#define hexdigitp(a) (digitp (a)                     \
+                      || ((a) >= 'A' && (a) <= 'F')  \
+                      || ((a) >= 'a' && (a) <= 'f'))
+#define atoi_1(p)   (*(p) - '0' )
+#define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
+/* assumes ASCII and pre-checked values */
+#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
+                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+/* Data used to associate an Assuan context with local server data */
+struct server_local_s {
+  ASSUAN_CONTEXT assuan_ctx;
+  int message_fd;
+};
+
+/* SETHASH <hexstring>
+
+  The client can use this command to tell the server about the data
+  (which usually is a hash) to be signed. */
+static int
+cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
+{
+  int n;
+  char *p;
+  CTRL ctrl = assuan_get_pointer (ctx);
+  unsigned char *buf;
+
+  /* parse the hash value */
+  for (p=line,n=0; hexdigitp (*p); p++, n++)
+    ;
+  if (*p)
+    return set_error (Parameter_Error, "invalid hexstring");
+  if ((n&1))
+    return set_error (Parameter_Error, "odd number of digits");
+  n /= 2;
+  if (n != 16 && n != 20 && n != 24 && n != 32)
+    return set_error (Parameter_Error, "unsupported length of hash");
+  if (n > MAX_DIGEST_LEN)
+    return set_error (Parameter_Error, "hash value to long");
+
+  buf = ctrl->digest.value;
+  ctrl->digest.valuelen = n;
+  for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
+    buf[n] = xtoi_2 (p);
+  for (; n < ctrl->digest.valuelen; n++)
+    buf[n] = 0;
+  return 0;
+}
+
+
+/* PKSIGN <options>
+
+   Perform the actual sign operation. Neither input nor output are
+   sensitive to to eavesdropping */
+static int
+cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
+{
+  int rc;
+  CTRL ctrl = assuan_get_pointer (ctx);
+
+  /* fixme: check that all required data is available */
+  rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
+  /* fixme: return an error */
+  return 0;
+}
+
+
+/* MESSAGE FD=<n>
+
+   Set the file descriptor to read a message which is used with
+   detached signatures */
+static int 
+cmd_message (ASSUAN_CONTEXT ctx, char *line)
+{
+#if 0
+  char *endp;
+  int fd;
+  CTRL ctrl = assuan_get_pointer (ctx);
+
+  if (strncmp (line, "FD=", 3))
+    return set_error (Syntax_Error, "FD=<n> expected");
+  line += 3;
+  if (!digitp (*line))
+    return set_error (Syntax_Error, "number required");
+  fd = strtoul (line, &endp, 10);
+  if (*endp)
+    return set_error (Syntax_Error, "garbage found");
+  if (fd == -1)
+    return set_error (No_Input, NULL);
+
+  ctrl->server_local->message_fd = fd;
+  return 0;
+#endif
+  return set_error (Not_Implemented, NULL);
+}
+
+
+\f
+/* Tell the assuan library about our commands */
+static int
+register_commands (ASSUAN_CONTEXT ctx)
+{
+  static struct {
+    const char *name;
+    int cmd_id;
+    int (*handler)(ASSUAN_CONTEXT, char *line);
+  } table[] = {
+    { "SETHASH",    0,  cmd_sethash },
+    { "PKSIGN",     0,  cmd_pksign },
+    { "",     ASSUAN_CMD_INPUT, NULL }, 
+    { "",     ASSUAN_CMD_OUTPUT, NULL }, 
+    { "MESSAGE",    0,  cmd_message },
+    { NULL }
+  };
+  int i, j, rc;
+
+  for (i=j=0; table[i].name; i++)
+    {
+      rc = assuan_register_command (ctx,
+                                    table[i].cmd_id? table[i].cmd_id
+                                                   : (ASSUAN_CMD_USER + j++),
+                                    table[i].name, table[i].handler);
+      if (rc)
+        return rc;
+    } 
+  return 0;
+}
+
+
+/* Startup the server */
+void
+start_command_handler (void)
+{
+  int rc;
+  int filedes[2];
+  ASSUAN_CONTEXT ctx;
+  struct server_control_s ctrl;
+
+  memset (&ctrl, 0, sizeof ctrl);
+
+  /* For now we use a simple pipe based server so that we can work
+     from scripts.  We will later add options to run as a daemon and
+     wait for requests on a Unix domain socket */
+  filedes[0] = 0;
+  filedes[1] = 1;
+  rc = assuan_init_pipe_server (&ctx, filedes);
+  if (rc)
+    {
+      log_error ("failed to initialize the server: %s\n",
+                 assuan_strerror(rc));
+      agent_exit (2);
+    }
+  rc = register_commands (ctx);
+  if (rc)
+    {
+      log_error ("failed to the register commands with Assuan: %s\n",
+                 assuan_strerror(rc));
+      agent_exit (2);
+    }
+
+  assuan_set_pointer (ctx, &ctrl);
+  ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
+  ctrl.server_local->assuan_ctx = ctx;
+  ctrl.server_local->message_fd = -1;
+
+  log_info ("Assuan started\n");
+  for (;;)
+    {
+      rc = assuan_accept (ctx);
+      if (rc == -1)
+        {
+          log_info ("Assuan terminated\n");
+          break;
+        }
+      else if (rc)
+        {
+          log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
+          break;
+        }
+      
+      rc = assuan_process (ctx);
+      if (rc)
+        {
+          log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
+          continue;
+        }
+    }
+
+
+  assuan_deinit_pipe_server (ctx);
+}
+
index b0c6c95..4215789 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
-/*
- * How to use the client mode:
- *  printf '\0\0\0\002AAAAAAAAAAAAAAAAAAAAAPlease enter the passphrase for\n 
- *          key 0x12345678\nJoe Hacker <joe@hackworld.foo>\n' 
- *     | ./gpg-agent --client | od
- * Or use a builtin command to shut the agent down.
- *   ./gpg-agent --shutdown | od
- *
- */
-
 #include <config.h>
 
 #include <stdio.h>
 
 #include <gcrypt.h>
 
-#include "util.h"
+#include "agent.h"
 #include "../assuan/assuan.h" /* malloc hooks */
-#include "i18n.h"
+
+
+#define N_(a) a
+#define _(a) a
 
 
 enum cmd_and_opt_values 
@@ -72,6 +65,7 @@ enum cmd_and_opt_values
 aTest };
 
 
+
 static ARGPARSE_OPTS opts[] = {
   
   { 301, NULL, 0, N_("@Options:\n ") },
@@ -95,17 +89,6 @@ static ARGPARSE_OPTS opts[] = {
 };
 
 
-static struct {
-  const char *homedir;
-  int client;
-  int verbose;
-  int quiet;
-  unsigned int debug;
-  int nodetach;
-  int grab;
-  const char *logfile;
-  int csh_style;
-} opt;
 
 typedef struct {
     int used;
@@ -231,8 +214,13 @@ main (int argc, char **argv )
   int greeting = 0;
   int nogreeting = 0;
   int server_mode = 0;
+  int client = 0;
   int do_shutdown = 0;
   int do_flush = 0;
+  int nodetach = 0;
+  int grab = 0;
+  int csh_style = 0;
+  char *logfile = NULL;
 
   set_strusage( my_strusage );
   /*   log_set_name ("gpg-agent"); */
@@ -252,7 +240,7 @@ main (int argc, char **argv )
 
   shell = getenv("SHELL");
   if (shell && strlen(shell) >= 3 && !strcmp(shell+strlen(shell)-3, "csh") )
-    opt.csh_style = 1;
+    csh_style = 1;
   
   opt.homedir = getenv("GNUPGHOME");
   if (!opt.homedir || !*opt.homedir)
@@ -263,7 +251,7 @@ main (int argc, char **argv )
       opt.homedir = "~/.gnupg-test";
 #endif
     }
-  opt.grab = 1;
+  grab = 1;
 
   /* check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -345,14 +333,14 @@ main (int argc, char **argv )
         case oNoVerbose: opt.verbose = 0; break;
         case oNoOptions: break; /* no-options */
         case oHomedir: opt.homedir = pargs.r.ret_str; break;
-        case oNoDetach: opt.nodetach = 1; break;
-        case oNoGrab: opt.grab = 0; break;
-        case oClient: opt.client = 1; break;
-        case oShutdown: opt.client = 1; do_shutdown = 1; break;
-        case oFlush: opt.client = 1; do_flush = 1; break;
-        case oLogFile: opt.logfile = pargs.r.ret_str; break;
-        case oCsh: opt.csh_style = 1; break;
-        case oSh: opt.csh_style = 0; break;
+        case oNoDetach: nodetach = 1; break;
+        case oNoGrab: grab = 0; break;
+        case oClient: client = 1; break;
+        case oShutdown: client = 1; do_shutdown = 1; break;
+        case oFlush: client = 1; do_flush = 1; break;
+        case oLogFile: logfile = pargs.r.ret_str; break;
+        case oCsh: csh_style = 1; break;
+        case oSh: csh_style = 0; break;
         case oServer: server_mode = 1; break;
 
         default : pargs.err = configfp? 1:2; break;
@@ -390,7 +378,7 @@ main (int argc, char **argv )
       exit (1);
     }
    
-  if (opt.client)
+  if (client)
     { /* a client for testing this agent */
 #if 0 /* FIXME: We are going to use assuan here */
       int fd;
@@ -444,6 +432,10 @@ main (int argc, char **argv )
       close (fd );
 #endif
     }
+  else if (server_mode)
+    { /* for now this is the simple pipe based server */
+      start_command_handler ();
+    }
   else
     { /* regular server mode */
       int listen_fd;
@@ -495,7 +487,7 @@ main (int argc, char **argv )
             }
           /* print the environment string, so that the caller can use
              eval to set it */
-          if (opt.csh_style)
+          if (csh_style)
             {
               *strchr (infostr, '=') = ' ';
               printf ( "setenv %s\n", infostr);
@@ -510,7 +502,7 @@ main (int argc, char **argv )
       if ( (opt.debug & 1) )
         sleep( 20 ); /* give us some time to attach gdb to the child */
 
-      if (opt.logfile)
+      if (logfile)
         {
           /* FIXME:log_set_logfile (opt.logfile, -1);*/
         }
@@ -522,7 +514,7 @@ main (int argc, char **argv )
           exit (1);
         }
 
-      if ( !opt.nodetach )
+      if ( !nodetach )
         {
           for (i=0 ; i <= 2; i++ ) 
             {
@@ -589,6 +581,28 @@ main (int argc, char **argv )
   return 0;
 }
 
+void
+agent_exit (int rc)
+{
+  #if 0
+#warning no update_random_seed_file
+  update_random_seed_file();
+  #endif
+#if 0
+  /* at this time a bit annoying */
+  if (opt.debug & DBG_MEMSTAT_VALUE)
+    {
+      gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
+      gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
+    }
+  if (opt.debug)
+    gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
+#endif
+  gcry_control (GCRYCTL_TERM_SECMEM );
+  rc = rc? rc : log_get_errorcount(0)? 2 : 0;
+  exit (rc);
+}
+
 
 static int
 start_listening (const char *name)
diff --git a/agent/pksign.c b/agent/pksign.c
new file mode 100644 (file)
index 0000000..69093a0
--- /dev/null
@@ -0,0 +1,39 @@
+/* pksign.c - public key signing (well, acually using a secret key)
+ *     Copyright (C) 2001 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "agent.h"
+
+
+/* SIGN whatever information we have accumulated in CTRL and write it back to 
+   OUTFP. */
+int
+agent_pksign (CTRL ctrl, FILE *outfp) 
+{
+
+  return -1;
+}