A small step for GnuPG but a huge leap for error codes.
authorWerner Koch <wk@gnupg.org>
Thu, 5 Jun 2003 07:14:21 +0000 (07:14 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 5 Jun 2003 07:14:21 +0000 (07:14 +0000)
(Sorry, it does not build currently - I need to check it in to avoid
duplicate work.)

ChangeLog
Makefile.am
configure.ac
g10/ChangeLog
g10/Makefile.am
g10/call-agent.c [new file with mode: 0644]
g10/call-agent.h [new file with mode: 0644]
g10/g10.c
g10/gpg.h [new file with mode: 0644]
g10/options.h
include/errors.h

index dd9c320..d2a1453 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2003-06-04  Werner Koch  <wk@gnupg.org>
+
+       * configure.ac, Makefile.am: Enable building of gpg.
+
 2003-04-29  Werner Koch  <wk@gnupg.org>
 
        * configure.ac: Build a limited version of scdaemon if libopensc
index d9a0926..74e6220 100644 (file)
@@ -23,6 +23,11 @@ ACLOCAL_AMFLAGS = -I m4
 
 EXTRA_DIST = scripts/config.rpath  autogen.sh
 
+if BUILD_GPG
+gpg = g10
+else
+gpg =
+endif
 if BUILD_GPGSM
 sm = sm
 else
@@ -39,9 +44,10 @@ else
 scd =
 endif
 
-SUBDIRS = m4  intl jnlib common kbx ${sm} ${agent} ${scd} po doc tests
+SUBDIRS = m4  intl jnlib common kbx ${gpg} ${sm} ${agent} ${scd} po doc tests
 
 
 dist-hook:
        @set -e; echo "$(VERSION)" > $(distdir)/VERSION
 
+
index e075d71..2f0bf9d 100644 (file)
@@ -44,7 +44,7 @@ have_ksba=no
 have_opensc=no
 have_pth=no
 
-GNUPG_BUILD_PROGRAM(gpg, no)
+GNUPG_BUILD_PROGRAM(gpg, yes)
 GNUPG_BUILD_PROGRAM(gpgsm, yes)
 GNUPG_BUILD_PROGRAM(agent, yes)
 GNUPG_BUILD_PROGRAM(scdaemon, yes)
@@ -363,6 +363,7 @@ if test "$build_scdaemon" = "yes"; then
 fi
 
 
+AM_CONDITIONAL(BUILD_GPG,   test "$build_gpg" = "yes")
 AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes")
 AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes")
 AM_CONDITIONAL(BUILD_SCDAEMON, test "$build_scdaemon" = "yes")
@@ -375,6 +376,7 @@ intl/Makefile
 jnlib/Makefile
 common/Makefile
 kbx/Makefile
+g10/Makefile
 sm/Makefile
 agent/Makefile
 scd/Makefile
index 3db1b0e..176ec10 100644 (file)
@@ -1,3 +1,10 @@
+2003-06-04  Werner Koch  <wk@gnupg.org>
+
+       * Makefile.am: Add new files, link gpg with libgpg-error.
+       * g10.c, options.h: New option --agent-program.
+       * call-agent.c: New.
+       * gpg.h, call-agent.h: New.
+
 2003-06-03  David Shaw  <dshaw@jabberwocky.com>
 
        * options.h, g10.c (main), keylist.c (list_keyblock_print): Add
index a7e3117..9143874 100644 (file)
@@ -24,16 +24,17 @@ EXTRA_DIST = options.skel
 # it seems that we can't use this with automake 1.5
 #OMIT_DEPENDENCIES = zlib.h zconf.h
 libexecdir = @libexecdir@/@PACKAGE@
-if ! HAVE_DOSISH_SYSTEM
-AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
-endif
+# FIXME: Windows support currently not enabled
+#if ! HAVE_DOSISH_SYSTEM
+#AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
+#endif
 needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
 
 #noinst_PROGRAMS = gpgd
 bin_PROGRAMS = gpg gpgv
 
 common_source =  \
-             global.h          \
+             global.h gpg.h    \
              build-packet.c    \
              compress.c        \
              filter.h          \
@@ -93,6 +94,7 @@ gpg_SOURCES  = g10.c          \
              keyserver.c       \
              keyserver-internal.h \
              photoid.c photoid.h \
+             call-agent.c call-agent.h \
              exec.c exec.h
 
 gpgv_SOURCES = gpgv.c           \
@@ -107,8 +109,7 @@ gpgv_SOURCES = gpgv.c           \
 #             $(common_source)
 
 LDADD =  $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@
-# gpg gets LIBOBJS to add in mkdtemp if the platform doesn't have it
-gpg_LDADD = @LIBOBJS@ $(LDADD) @DLLIBS@ @EGDLIBS@
+gpg_LDADD = $(LDADD) @DLLIBS@ @EGDLIBS@ -lgpg-error
 
 $(PROGRAMS): $(needed_libs)
 
diff --git a/g10/call-agent.c b/g10/call-agent.c
new file mode 100644 (file)
index 0000000..6cc514d
--- /dev/null
@@ -0,0 +1,407 @@
+/* call-agent.c - divert operations to the agent
+ *     Copyright (C) 2001, 2002, 2003 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
+ */
+
+#if 0  /* lety Emacs display a red warning */
+#error fixme: this shares a lof of code with the file in ../sm
+#endif
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h> 
+#include <time.h>
+#include <assert.h>
+#include <gcrypt.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <assuan.h>
+
+#include "gpg.h"
+#include "i18n.h"
+
+static ASSUAN_CONTEXT agent_ctx = NULL;
+static int force_pipe_server = 0;
+
+struct cipher_parm_s {
+  ASSUAN_CONTEXT ctx;
+  const char *ciphertext;
+  size_t ciphertextlen;
+};
+
+struct genkey_parm_s {
+  ASSUAN_CONTEXT ctx;
+  const char *sexp;
+  size_t sexplen;
+};
+
+struct learn_parm_s {
+  int error;
+  ASSUAN_CONTEXT ctx;
+  struct membuf *data;
+};
+
+\f
+/* Try to connect to the agent via socket or fork it off and work by
+   pipes.  Handle the server's initial greeting */
+static int
+start_agent (void)
+{
+  int rc = 0;
+  char *infostr, *p;
+  ASSUAN_CONTEXT ctx;
+  char *dft_display = NULL;
+  char *dft_ttyname = NULL;
+  char *dft_ttytype = NULL;
+  char *old_lc = NULL;
+  char *dft_lc = NULL;
+
+  if (agent_ctx)
+    return 0; /* fixme: We need a context for each thread or serialize
+                 the access to the agent. */
+
+  infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
+  if (!infostr)
+    {
+      const char *pgmname;
+      const char *argv[3];
+      int no_close_list[3];
+      int i;
+
+      if (opt.verbose)
+        log_info (_("no running gpg-agent - starting one\n"));
+
+      if (fflush (NULL))
+        {
+          gpg_error_t tmperr = gpg_error_from_errno (errno);
+          log_error ("error flushing pending output: %s\n", strerror (errno));
+          return tmperr;
+        }
+
+      if (!opt.agent_program || !*opt.agent_program)
+        opt.agent_program = GNUPG_DEFAULT_AGENT;
+      if ( !(pgmname = strrchr (opt.agent_program, '/')))
+        pgmname = opt.agent_program;
+      else
+        pgmname++;
+
+      argv[0] = pgmname;
+      argv[1] = "--server";
+      argv[2] = NULL;
+
+      i=0;
+      if (log_get_fd () != -1)
+        no_close_list[i++] = log_get_fd ();
+      no_close_list[i++] = fileno (stderr);
+      no_close_list[i] = -1;
+
+      /* connect to the agent and perform initial handshaking */
+      rc = assuan_pipe_connect (&ctx, opt.agent_program, (char**)argv,
+                                no_close_list);
+    }
+  else
+    {
+      int prot;
+      int pid;
+
+      infostr = xstrdup (infostr);
+      if ( !(p = strchr (infostr, ':')) || p == infostr)
+        {
+          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+          xfree (infostr);
+          force_pipe_server = 1;
+          return start_agent ();
+        }
+      *p++ = 0;
+      pid = atoi (p);
+      while (*p && *p != ':')
+        p++;
+      prot = *p? atoi (p+1) : 0;
+      if (prot != 1)
+        {
+          log_error (_("gpg-agent protocol version %d is not supported\n"),
+                     prot);
+          xfree (infostr);
+          force_pipe_server = 1;
+          return start_agent ();
+        }
+
+      rc = assuan_socket_connect (&ctx, infostr, pid);
+      xfree (infostr);
+      if (rc == ASSUAN_Connect_Failed)
+        {
+          log_error (_("can't connect to the agent - trying fall back\n"));
+          force_pipe_server = 1;
+          return start_agent ();
+        }
+    }
+
+  if (rc)
+    {
+      log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
+      return gpg_error (GPG_ERR_NO_AGENT);
+    }
+  agent_ctx = ctx;
+
+  if (DBG_ASSUAN)
+    log_debug ("connection to agent established\n");
+
+  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
+  if (rc)
+    return map_assuan_err (rc);
+
+  dft_display = getenv ("DISPLAY");
+  if (opt.display || dft_display)
+    {
+      char *optstr;
+      if (asprintf (&optstr, "OPTION display=%s",
+                   opt.display ? opt.display : dft_display) < 0)
+       return OUT_OF_CORE (errno);
+      rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                           NULL);
+      free (optstr);
+      if (rc)
+       return map_assuan_err (rc);
+    }
+  if (!opt.ttyname)
+    {
+      dft_ttyname = getenv ("GPG_TTY");
+      if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
+        dft_ttyname = ttyname (0);
+    }
+  if (opt.ttyname || dft_ttyname)
+    {
+      char *optstr;
+      if (asprintf (&optstr, "OPTION ttyname=%s",
+                   opt.ttyname ? opt.ttyname : dft_ttyname) < 0)
+       return OUT_OF_CORE (errno);
+      rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                           NULL);
+      free (optstr);
+      if (rc)
+       return map_assuan_err (rc);
+    }
+  dft_ttytype = getenv ("TERM");
+  if (opt.ttytype || (dft_ttyname && dft_ttytype))
+    {
+      char *optstr;
+      if (asprintf (&optstr, "OPTION ttytype=%s",
+                   opt.ttyname ? opt.ttytype : dft_ttytype) < 0)
+       return OUT_OF_CORE (errno);
+      rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                           NULL);
+      free (optstr);
+      if (rc)
+       return map_assuan_err (rc);
+    }
+#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
+  old_lc = setlocale (LC_CTYPE, NULL);
+  if (old_lc)
+    {
+      old_lc = strdup (old_lc);
+      if (!old_lc)
+        return OUT_OF_CORE (errno);
+    }
+  dft_lc = setlocale (LC_CTYPE, "");
+#endif
+  if (opt.lc_ctype || (dft_ttyname && dft_lc))
+    {
+      char *optstr;
+      if (asprintf (&optstr, "OPTION lc-ctype=%s",
+                   opt.lc_ctype ? opt.lc_ctype : dft_lc) < 0)
+       rc = OUT_OF_CORE (errno);
+      else
+       {
+         rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                               NULL);
+         free (optstr);
+         if (rc)
+           rc = map_assuan_err (rc);
+       }
+    }
+#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
+  if (old_lc)
+    {
+      setlocale (LC_CTYPE, old_lc);
+      free (old_lc);
+    }
+#endif
+  if (rc)
+    return rc;
+#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
+  old_lc = setlocale (LC_MESSAGES, NULL);
+  if (old_lc)
+    {
+      old_lc = strdup (old_lc);
+      if (!old_lc)
+        return OUT_OF_CORE (errno);
+    }
+  dft_lc = setlocale (LC_MESSAGES, "");
+#endif
+  if (opt.lc_messages || (dft_ttyname && dft_lc))
+    {
+      char *optstr;
+      if (asprintf (&optstr, "OPTION lc-messages=%s",
+                   opt.lc_messages ? opt.lc_messages : dft_lc) < 0)
+       rc = OUT_OF_CORE (errno);
+      else
+       {
+         rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                               NULL);
+         free (optstr);
+         if (rc)
+           rc = map_assuan_err (rc);
+       }
+    }
+#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
+  if (old_lc)
+    {
+      setlocale (LC_MESSAGES, old_lc);
+      free (old_lc);
+    }
+#endif
+
+  return rc;
+}
+
+
+static AssuanError
+membuf_data_cb (void *opaque, const void *buffer, size_t length)
+{
+  membuf_t *data = opaque;
+
+  if (buffer)
+    put_membuf (data, buffer, length);
+  return 0;
+}
+  
+
+\f
+#if 0
+/* Handle a KEYPARMS inquiry.  Note, we only send the data,
+   assuan_transact takes care of flushing and writing the end */
+static AssuanError
+inq_genkey_parms (void *opaque, const char *keyword)
+{
+  struct genkey_parm_s *parm = opaque; 
+  AssuanError rc;
+
+  rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
+  return rc; 
+}
+
+
+\f
+/* Call the agent to generate a new key */
+int
+agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
+{
+  int rc;
+  struct genkey_parm_s gk_parm;
+  membuf_t data;
+  size_t len;
+  char *buf;
+
+  *r_pubkey = NULL;
+  rc = start_agent ();
+  if (rc)
+    return rc;
+
+  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL,
+                        NULL, NULL, NULL, NULL);
+  if (rc)
+    return map_assuan_err (rc);
+
+  init_membuf (&data, 1024);
+  gk_parm.ctx = agent_ctx;
+  gk_parm.sexp = keyparms;
+  gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
+  if (!gk_parm.sexplen)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  rc = assuan_transact (agent_ctx, "GENKEY",
+                        membuf_data_cb, &data, 
+                        inq_genkey_parms, &gk_parm, NULL, NULL);
+  if (rc)
+    {
+      xfree (get_membuf (&data, &len));
+      return map_assuan_err (rc);
+    }
+  buf = get_membuf (&data, &len);
+  if (!buf)
+    return gpg_error (GPG_ERR_ENOMEM);
+  if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
+    {
+      xfree (buf);
+      return gpg_error (GPG_ERR_INV_SEXP);
+    }
+  *r_pubkey = buf;
+  return 0;
+}
+#endif /*0*/
+
+
+\f
+/* Ask the agent whether the corresponding secret key is available for
+   the given keygrip. */
+int
+agent_havekey (const char *hexkeygrip)
+{
+  int rc;
+  char line[ASSUAN_LINELENGTH];
+
+  rc = start_agent ();
+  if (rc)
+    return rc;
+
+  if (!hexkeygrip || strlen (hexkeygrip) != 40)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
+  line[DIM(line)-1] = 0;
+
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  return map_assuan_err (rc);
+}
+
+\f
+/* Ask the agent to change the passphrase of the key identified by
+   HEXKEYGRIP. */
+int
+agent_passwd (const char *hexkeygrip)
+{
+  int rc;
+  char line[ASSUAN_LINELENGTH];
+
+  rc = start_agent ();
+  if (rc)
+    return rc;
+
+  if (!hexkeygrip || strlen (hexkeygrip) != 40)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
+  line[DIM(line)-1] = 0;
+
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  return map_assuan_err (rc);
+}
+
diff --git a/g10/call-agent.h b/g10/call-agent.h
new file mode 100644 (file)
index 0000000..fbb1195
--- /dev/null
@@ -0,0 +1,34 @@
+/* call-agent.h - Divert operations to the agent
+ * Copyright (C) 2003 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 GNUPG_G10_CALL_AGENT_H
+#define GNUPG_G10_CALL_AGENT_H 
+
+/* Check whether the secret key for the key identified by HEXKEYGRIP
+   is available.  Return 0 for yes or an error code. */
+int agent_havekey (const char *hexkeygrip);
+
+/* Ask the agent to let the user change the passphrase of the secret
+   key identified by HEXKEYGRIP. */
+int agent_passwd (const char *hexkeygrip);
+
+
+
+
+#endif /*GNUPG_G10_CALL_AGENT_H*/
index 8a7f09d..d17422c 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -303,6 +303,7 @@ enum cmd_and_opt_values { aNull = 0,
     oPersonalDigestPreferences,
     oPersonalCompressPreferences,
     oEmuMDEncodeBug,
+    oAgentProgram,
     oDisplay,
     oTTYname,
     oTTYtype,
@@ -610,6 +611,7 @@ static ARGPARSE_OPTS opts[] = {
     { oPersonalDigestPreferences,  "personal-digest-preferences", 2, "@"},
     { oPersonalCompressPreferences,  "personal-compress-preferences", 2, "@"},
     { oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
+    { oAgentProgram, "agent-program", 2 , "@" },
     { oDisplay,    "display",     2, "@" },
     { oTTYname,    "ttyname",     2, "@" },
     { oTTYtype,    "ttytype",     2, "@" },
@@ -1876,6 +1878,7 @@ main( int argc, char **argv )
           case oPersonalCompressPreferences:
            pers_compress_list=pargs.r.ret_str;
            break;
+          case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
           case oDisplay: opt.display = pargs.r.ret_str; break;
           case oTTYname: opt.ttyname = pargs.r.ret_str; break;
           case oTTYtype: opt.ttytype = pargs.r.ret_str; break;
diff --git a/g10/gpg.h b/g10/gpg.h
new file mode 100644 (file)
index 0000000..ca7699b
--- /dev/null
+++ b/g10/gpg.h
@@ -0,0 +1,33 @@
+/* gpg.h - top level include file for gpg etc.
+ * Copyright (C) 2003 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 GNUPG_G10_GPG_H
+#define GNUPG_G10_GPG_H 
+
+#ifdef GPG_ERR_SOURCE_DEFAULT
+#error GPG_ERR_SOURCE_DEFAULT already defined
+#endif
+#define GPG_ERR_SOURCE_DEFAULT  GPG_ERR_SOURCE_GPG
+#include <gpg-error.h>
+
+
+/* FIXME: merge this with global.h */
+
+
+#endif /*GNUPG_G10_GPG_H*/
index 1a70277..a68dc52 100644 (file)
@@ -79,7 +79,7 @@ struct {
     int completes_needed;
     int max_cert_depth;
     const char *homedir;
-
+    const char *agent_program; 
     char *display;      /* 5 options to be passed to the gpg-agent */
     char *ttyname;     
     char *ttytype;
index 0dde0f9..8e1de0f 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
-#ifndef G10_ERRORS_H
-#define G10_ERRORS_H
+#ifndef GNUPG_INCLUDE_ERRORS_H
+#define GNUPG_INCLUDE_ERRORS_H
+
+#if 0
+#error Remove this file after replacing all error codes with those
+#error from libgpg-error.  The numerical values are identical, though.
+#endif
 
 #define G10ERR_GENERAL        1
 #define G10ERR_UNKNOWN_PACKET  2
@@ -81,4 +86,4 @@
 char *strerror( int n );
 #endif
 
-#endif /*G10_ERRORS_H*/
+#endif /*GNUPG_INCLUDE_ERRORS_H*/