Implemented the --gen-key command as we can't use the gpgsm-gencert.sh under Windows.
authorWerner Koch <wk@gnupg.org>
Thu, 21 Jun 2007 18:44:48 +0000 (18:44 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 21 Jun 2007 18:44:48 +0000 (18:44 +0000)
33 files changed:
NEWS
TODO
agent/ChangeLog
agent/agent.h
agent/gpg-agent.c
common/ChangeLog
common/asshelp.c
common/asshelp.h
common/exechelp.c
common/membuf.c
common/membuf.h
common/ttyio.c
common/ttyio.h
common/util.h
doc/ChangeLog
doc/glossary.texi
doc/gpg-agent.texi
doc/gpgsm.texi
g10/ChangeLog
g10/call-agent.c
g10/gpg.h
g10/main.h
g10/sign.c
scd/ChangeLog
scd/scdaemon.h
sm/ChangeLog
sm/Makefile.am
sm/call-agent.c
sm/certreqgen-ui.c [new file with mode: 0644]
sm/certreqgen.c
sm/gpgsm.c
sm/gpgsm.h
sm/server.c

diff --git a/NEWS b/NEWS
index f547790..a567c58 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,9 @@ Noteworthy changes in version 2.0.5
 
  * Changes required for a port to Windows.
 
+ * The command --gen-key may now be used instead of the
+   gpgsm-gencert.sh script.
+
 
 Noteworthy changes in version 2.0.4 (2007-05-09)
 ------------------------------------------------
diff --git a/TODO b/TODO
index 698cec4..649dbf2 100644 (file)
--- a/TODO
+++ b/TODO
@@ -95,7 +95,7 @@
 
 * When requiring libksba 1.0.1
 ** Remove the extra GPG_ERR_NO_VALUE tests 
-   They have need added on 2006-10-18 to fix a libksba problem.
+   They have been added on 2006-10-18 to fix a libksba problem.
 
 * When switching to libgcrypt 1.3
 ** scd#encode_md_for_card, g10#encode_md_value, sm@do_encode_md
index 1956455..653bcd0 100644 (file)
@@ -1,3 +1,12 @@
+2007-06-21  Werner Koch  <wk@g10code.com>
+
+       * agent.h (ctrl_t): Remove.  It is now declared in ../common/util.h. 
+
+       * gpg-agent.c (check_for_running_agent): New arg SILENT.  Changed
+       all callers.
+       (create_server_socket): If the standard socket is in use check
+       whether a agent is running and avoid starting another one.
+
 2007-06-18  Marcus Brinkmann  <marcus@g10code.de>
 
        * gpg-agent.c (main): Percent escape pathname in --gpgconf-list
index cb1cca0..690a86d 100644 (file)
@@ -150,8 +150,6 @@ struct server_control_s
                         PKSIGN command to the scdaemon.  */
 };
 
-typedef struct server_control_s *ctrl_t;
-
 
 struct pin_entry_info_s 
 {
index a064692..360870f 100644 (file)
@@ -1,6 +1,6 @@
 /* gpg-agent.c  -  The GnuPG Agent
- *     Copyright (C) 2000, 2001, 2002, 2003, 2004,
- *                    2005 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006, 2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -93,7 +93,6 @@ enum cmd_and_opt_values
   oMinPassphraseLen,
   oUseStandardSocket,
   oNoUseStandardSocket,
-  oNoReuseStandardSocket,
 
   oIgnoreCacheForSigning,
   oAllowMarkTrusted,
@@ -131,8 +130,6 @@ static ARGPARSE_OPTS opts[] = {
   { oUseStandardSocket, "use-standard-socket", 0,
                       N_("use a standard location for the socket")},
   { oNoUseStandardSocket, "no-use-standard-socket", 0, "@"},
-  { oNoReuseStandardSocket, "no-reuse-standard-socket", 0, "@"},
-
   { oPinentryProgram, "pinentry-program", 2 ,
                                N_("|PGM|use PGM as the PIN-Entry program") },
   { oPinentryTouchFile, "pinentry-touch-file", 2 , "@" },
@@ -188,10 +185,6 @@ static char *socket_name;
 /* Name of the communication socket used for ssh-agent-emulation.  */
 static char *socket_name_ssh;
 
-/* If set to true and a standard socket is requested, we won't try to
-   bind to a socket which is already in use.  */
-static int no_reuse_standard_socket;
-
 /* Default values for options passed to the pinentry. */
 static char *default_display;
 static char *default_ttyname;
@@ -228,7 +221,7 @@ static void agent_init_default_ctrl (ctrl_t ctrl);
 static void agent_deinit_default_ctrl (ctrl_t ctrl);
 
 static void handle_connections (int listen_fd, int listen_fd_ssh);
-static int check_for_running_agent (int);
+static int check_for_running_agent (int silent, int mode);
 
 /* Pth wrapper function definitions. */
 GCRY_THREAD_OPTION_PTH_IMPL;
@@ -627,7 +620,6 @@ main (int argc, char **argv )
 
         case oUseStandardSocket: standard_socket = 1; break;
         case oNoUseStandardSocket: standard_socket = 0; break;
-        case oNoReuseStandardSocket: no_reuse_standard_socket = 1; break;
 
         case oKeepTTY: opt.keep_tty = 1; break;
         case oKeepDISPLAY: opt.keep_display = 1; break;
@@ -765,7 +757,7 @@ main (int argc, char **argv )
   if (!pipe_server && !is_daemon)
     {
       log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX); 
-      check_for_running_agent (0);
+      check_for_running_agent (0, 0);
       agent_exit (0);
     }
   
@@ -1264,17 +1256,32 @@ create_server_socket (int is_standard_name, char *name)
 
 #ifdef HAVE_W32_SYSTEM
   rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
-  if (is_standard_name && rc == -1 && errno == WSAEADDRINUSE
-      && !no_reuse_standard_socket)
+  if (is_standard_name && rc == -1 && errno == WSAEADDRINUSE)
     {
+      if (!check_for_running_agent (1, 1))
+        {
+          log_error (_("a gpg-agent is already running - "
+                      "not starting a new one\n"));
+          *name = 0; /* Inhibit removal of the socket by cleanup(). */
+          close (fd);
+          agent_exit (2);
+        }
+
       remove (name);
       rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
     }
 #else
   rc = bind (fd, (struct sockaddr*) serv_addr, len);
-  if (is_standard_name && rc == -1 && errno == EADDRINUSE  
-      && !no_reuse_standard_socket)
+  if (is_standard_name && rc == -1 && errno == EADDRINUSE)
     {
+      if (!check_for_running_agent (1, 1))
+        {
+          log_error (_("a gpg-agent is already running - "
+                      "not starting a new one\n"));
+          *name = 0; /* Inhibit removal of the socket by cleanup(). */
+          close (fd);
+          agent_exit (2);
+        }
       remove (name);
       rc = bind (fd, (struct sockaddr*) serv_addr, len);
     }
@@ -1288,7 +1295,7 @@ create_server_socket (int is_standard_name, char *name)
                  gpg_strerror (gpg_error_from_errno (errno)));
       
       close (fd);
-      if (is_standard_name && no_reuse_standard_socket)
+      if (is_standard_name)
         *name = 0; /* Inhibit removal of the socket by cleanup(). */
       agent_exit (2);
     }
@@ -1725,9 +1732,10 @@ handle_connections (int listen_fd, int listen_fd_ssh)
 
 
 /* Figure out whether an agent is available and running. Prints an
-   error if not.  Usually started with MODE 0. */
+   error if not.  If SILENT is true, no mesdsages are printed.  Usually
+   started with MODE 0.  Returns 0 if the agent is running. */
 static int
-check_for_running_agent (int mode)
+check_for_running_agent (int silent, int mode)
 {
   int rc;
   char *infostr, *p;
@@ -1739,9 +1747,10 @@ check_for_running_agent (int mode)
       infostr = getenv ("GPG_AGENT_INFO");
       if (!infostr || !*infostr)
         {
-          if (!check_for_running_agent (1))
+          if (!check_for_running_agent (silent, 1))
             return 0; /* Okay, its running on the standard socket. */
-          log_error (_("no gpg-agent running in this session\n"));
+          if (!silent)
+            log_error (_("no gpg-agent running in this session\n"));
           return -1;
         }
 
@@ -1749,9 +1758,10 @@ check_for_running_agent (int mode)
       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
         {
           xfree (infostr);
-          if (!check_for_running_agent (1))
+          if (!check_for_running_agent (silent, 1))
             return 0; /* Okay, its running on the standard socket. */
-          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+          if (!silent)
+            log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
           return -1;
         }
 
@@ -1763,9 +1773,10 @@ check_for_running_agent (int mode)
       if (prot != 1)
         {
           xfree (infostr);
-          log_error (_("gpg-agent protocol version %d is not supported\n"),
-                     prot);
-          if (!check_for_running_agent (1))
+          if (!silent)
+            log_error (_("gpg-agent protocol version %d is not supported\n"),
+                       prot);
+          if (!check_for_running_agent (silent, 1))
             return 0; /* Okay, its running on the standard socket. */
           return -1;
         }
@@ -1781,15 +1792,15 @@ check_for_running_agent (int mode)
   xfree (infostr);
   if (rc)
     {
-      if (!mode && !check_for_running_agent (1))
+      if (!mode && !check_for_running_agent (silent, 1))
         return 0; /* Okay, its running on the standard socket. */
 
-      if (!mode)
+      if (!mode && !silent)
         log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
       return -1;
     }
 
-  if (!opt.quiet)
+  if (!opt.quiet && !silent)
     log_info ("gpg-agent running and available\n");
 
   assuan_disconnect (ctx);
index 3f8fa41..e80e703 100644 (file)
@@ -1,3 +1,17 @@
+2007-06-21  Werner Koch  <wk@g10code.com>
+
+       * membuf.h (get_membuf_len): New.
+
+       * membuf.c (init_membuf_secure): Really allocate in secure memory.
+       (put_membuf_str): New.
+
+       * ttyio.c (tty_getf): New.
+
+       * util.h (ctrl_t): Declare it here.
+
+       * asshelp.c (start_new_gpg_agent): New.  Based on code from
+       ../sm/call-agent.c
+
 2007-06-20  Werner Koch  <wk@g10code.com>
 
        * sysutils.c (gnupg_sleep): New.
index 54d7224..0241280 100644 (file)
 #include <locale.h>
 #endif
 
+#include "i18n.h"
 #include "util.h"
-
+#include "exechelp.h"
+#include "sysutils.h"
+#include "errors.h"  /* FIXME: This one conatisn only status code - rename it*/
 #include "asshelp.h"
 
 
@@ -164,3 +167,182 @@ send_pinentry_environment (assuan_context_t ctx,
   return 0;
 }
 
+
+/* Try to connect to the agent via socket or fork it off and work by
+   pipes.  Handle the server's initial greeting.  Returns a new assuan
+   context at R_CTX or an error code. */
+gpg_error_t
+start_new_gpg_agent (assuan_context_t *r_ctx,
+                     gpg_err_source_t errsource,
+                     const char *homedir,
+                     const char *agent_program,
+                     const char *opt_display,
+                     const char *opt_ttyname,
+                     const char *opt_ttytype,
+                     const char *opt_lc_ctype,
+                     const char *opt_lc_messages,
+                     int verbose, int debug,
+                     gpg_error_t (*status_cb)(ctrl_t, int, ...),
+                     ctrl_t status_cb_arg)
+{
+  /* If we ever failed to connect via a socket we will force the use
+     of the pipe based server for the lifetime of the process.  */
+  static int force_pipe_server = 0;
+
+  gpg_error_t rc = 0;
+  char *infostr, *p;
+  assuan_context_t ctx;
+
+  *r_ctx = NULL;
+
+ restart:
+  infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
+  if (!infostr || !*infostr)
+    {
+      char *sockname;
+
+      /* First check whether we can connect at the standard
+         socket.  */
+      sockname = make_filename (homedir, "S.gpg-agent", NULL);
+      rc = assuan_socket_connect (&ctx, sockname, 0);
+
+      if (rc)
+        {
+          /* With no success start a new server.  */
+          if (verbose)
+            log_info (_("no running gpg-agent - starting one\n"));
+          
+          if (status_cb)
+            status_cb (status_cb_arg, STATUS_PROGRESS, 
+                       "starting_agent ? 0 0", NULL);
+          
+          if (fflush (NULL))
+            {
+              gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
+              log_error ("error flushing pending output: %s\n",
+                         strerror (errno));
+              xfree (sockname);
+              return tmperr;
+            }
+          
+          if (!agent_program || !*agent_program)
+            agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
+
+#ifdef HAVE_W32_SYSTEM
+          {
+            /* Under Windows we start the server in daemon mode.  This
+               is because the default is to use the standard socket
+               and thus there is no need for the GPG_AGENT_INFO
+               envvar.  This is possible as we don't have a real unix
+               domain socket but use a plain file and thus there is no
+               need to care about non-local file systems. */
+            const char *argv[3];
+
+            argv[0] = "--daemon";
+            argv[1] = "--use-standard-socket"; 
+            argv[2] = NULL;  
+
+            rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
+            if (rc)
+              log_debug ("failed to start agent `%s': %s\n",
+                         agent_program, gpg_strerror (rc));
+            else
+              {
+                /* Give the agent some time to prepare itself. */
+                gnupg_sleep (3);
+                /* Now try again to connect the agent.  */
+                rc = assuan_socket_connect (&ctx, sockname, 0);
+              }
+          }
+#else /*!HAVE_W32_SYSTEM*/
+          {
+            const char *pgmname;
+            const char *argv[3];
+            int no_close_list[3];
+            int i;
+
+            if ( !(pgmname = strrchr (agent_program, '/')))
+              pgmname = 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, agent_program, argv,
+                                      no_close_list);
+          }
+#endif /*!HAVE_W32_SYSTEM*/
+        }
+      xfree (sockname);
+    }
+  else
+    {
+      int prot;
+      int pid;
+
+      infostr = xstrdup (infostr);
+      if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
+        {
+          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+          xfree (infostr);
+          force_pipe_server = 1;
+          goto restart;
+        }
+      *p++ = 0;
+      pid = atoi (p);
+      while (*p && *p != PATHSEP_C)
+        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;
+          goto restart;
+        }
+
+      rc = assuan_socket_connect (&ctx, infostr, pid);
+      xfree (infostr);
+      if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
+        {
+          log_info (_("can't connect to the agent - trying fall back\n"));
+          force_pipe_server = 1;
+          goto restart;
+        }
+    }
+
+  if (rc)
+    {
+      log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
+      return gpg_error (GPG_ERR_NO_AGENT);
+    }
+
+  if (debug)
+    log_debug ("connection to agent established\n");
+
+  rc = assuan_transact (ctx, "RESET",
+                        NULL, NULL, NULL, NULL, NULL, NULL);
+  if (!rc)
+    rc = send_pinentry_environment (ctx, errsource,
+                                    opt_display, opt_ttyname, opt_ttytype,
+                                    opt_lc_ctype, opt_lc_messages);
+  if (rc)
+    {
+      assuan_disconnect (ctx);
+      return rc;
+    }
+
+  *r_ctx = ctx;
+  return 0;
+}
+
index 9f4b580..adf81f9 100644 (file)
@@ -34,5 +34,21 @@ send_pinentry_environment (assuan_context_t ctx,
                            const char *opt_lc_ctype,
                            const char *opt_lc_messages);
 
+/* This fucntion is used by the call-agent.c modules to fire up a new
+   agent.  What a parameter list ;-).  */
+gpg_error_t
+start_new_gpg_agent (assuan_context_t *r_ctx,
+                     gpg_err_source_t errsource,
+                     const char *homedir,
+                     const char *agent_program,
+                     const char *opt_display,
+                     const char *opt_ttyname,
+                     const char *opt_ttytype,
+                     const char *opt_lc_ctype,
+                     const char *opt_lc_messages,
+                     int verbose, int debug,
+                     gpg_error_t (*status_cb)(ctrl_t, int, ...),
+                     ctrl_t status_cb_arg);
+
 
 #endif /*GNUPG_COMMON_ASSHELP_H*/
index d0be840..c488e29 100644 (file)
@@ -593,7 +593,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
                       cmdline,       /* Command line arguments.  */
                       &sec_attr,     /* Process security attributes.  */
                       &sec_attr,     /* Thread security attributes.  */
-                      FALSE,          /* Inherit handles.  */
+                      FALSE,         /* Inherit handles.  */
                       cr_flags,      /* Creation flags.  */
                       NULL,          /* Environment.  */
                       NULL,          /* Use current drive/directory.  */
index 5101459..eb436c4 100644 (file)
@@ -52,7 +52,7 @@ init_membuf_secure (membuf_t *mb, int initiallen)
   mb->len = 0;
   mb->size = initiallen;
   mb->out_of_core = 0;
-  mb->buf = xtrymalloc (initiallen);
+  mb->buf = xtrymalloc_secure (initiallen);
   if (!mb->buf)
     mb->out_of_core = errno;
 }
@@ -87,6 +87,13 @@ put_membuf (membuf_t *mb, const void *buf, size_t len)
 }
 
 
+void
+put_membuf_str (membuf_t *mb, const char *string)
+{
+  put_membuf (mb, string, strlen (string));
+}
+
+
 void *
 get_membuf (membuf_t *mb, size_t *len)
 {
index f9c08a4..906ae15 100644 (file)
@@ -34,10 +34,13 @@ struct private_membuf_s
 
 typedef struct private_membuf_s membuf_t;
 
+/* Return the current length of the membuf.  */
+#define get_membuf_len(a) ((a)->len)
 
 void init_membuf (membuf_t *mb, int initiallen);
 void init_membuf_secure (membuf_t *mb, int initiallen);
 void put_membuf  (membuf_t *mb, const void *buf, size_t len);
+void put_membuf_str (membuf_t *mb, const char *string);
 void *get_membuf (membuf_t *mb, size_t *len);
 
 
index 831ad90..98a4614 100644 (file)
@@ -50,6 +50,7 @@
 
 #include "util.h"
 #include "ttyio.h"
+#include "estream-printf.h"
 #include "common-defs.h"
 
 #define CONTROL_D ('D' - 'A' + 1)
@@ -243,7 +244,7 @@ tty_printf( const char *fmt, ... )
 }
 
 
-/* Same as tty_printf but if FP is not NULL, behave like a regualr
+/* Same as tty_printf but if FP is not NULL, behave like a regular
    fprintf. */
 void
 tty_fprintf (FILE *fp, const char *fmt, ... )
@@ -563,6 +564,26 @@ tty_get( const char *prompt )
     return do_get ( prompt, 0 );
 }
 
+/* Variable argument version of tty_get.  The prompt is is actually a
+   format string with arguments.  */
+char *
+tty_getf (const char *promptfmt, ... )
+{
+  va_list arg_ptr;
+  char *prompt;
+  char *answer;
+
+  va_start (arg_ptr, promptfmt);
+  if (estream_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
+    log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
+  va_end (arg_ptr);
+  answer = tty_get (prompt);
+  xfree (prompt);
+  return answer;
+}
+
+
+
 char *
 tty_get_hidden( const char *prompt )
 {
index d93906e..eed6b09 100644 (file)
@@ -31,9 +31,12 @@ void tty_printf (const char *fmt, ... )
                  __attribute__ ((format (printf,1,2)));
 void tty_fprintf (FILE *fp, const char *fmt, ... )
                  __attribute__ ((format (printf,2,3)));
+char *tty_getf (const char *promptfmt, ... )
+                 __attribute__ ((format (printf,1,2)));
 #else
 void tty_printf (const char *fmt, ... );
 void tty_fprintf (FILE *fp, const char *fmt, ... );
+char *tty_getf (const char *promptfmt, ... );
 #endif
 void tty_print_string (const unsigned char *p, size_t n);
 void tty_print_utf8_string (const unsigned char *p, size_t n);
index 42df127..3985821 100644 (file)
@@ -46,7 +46,6 @@
 #define asprintf estream_asprintf
 #define vasprintf estream_vasprintf
 
-
 /* GCC attributes.  */
 #if __GNUC__ >= 4 
 # define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
@@ -246,5 +245,10 @@ ttyname (int fd)
 #define xtoi_4(p)   ((xtoi_2(p) * 256) + xtoi_2((p)+2))
 
 
+/*-- Forward declaration of the commonly used server control structure.  */
+/*   (We need it here as it is used by some callback prototypes.) */
+struct server_control_s;
+typedef struct server_control_s *ctrl_t;
+
 
 #endif /*GNUPG_COMMON_UTIL_H*/
index a87680b..27546e0 100644 (file)
@@ -1,3 +1,8 @@
+2007-06-21  Werner Koch  <wk@g10code.com>
+
+       * gpgsm.texi (Certificate Management): Changed description of
+       --gen-key.
+
 2007-06-19  Werner Koch  <wk@g10code.com>
 
        * glossary.texi (Glossary): Describe PSE.
index 6eede19..22bd7ad 100644 (file)
@@ -16,6 +16,11 @@ certificates.
      The @emph{Certificate Revocation List} is a list containing
 certificates revoked by the issuer.
 
+@item CSR
+     The @emph{Certificate Signing Request} is a message send to a CA to
+ask them to issue a new certificate.  The data format of such a signing
+request is called PCKS#10.
+
 @item Keygrip
       This term is used by GnuPG to describe a 20 byte hash value used
 to identify a certain key without referencing to a concrete protocol.
index 85ce1ac..e9ef3a9 100644 (file)
@@ -369,20 +369,16 @@ this option at runtime does not kill an already forked scdaemon.
 
 @item --use-standard-socket
 @itemx --no-use-standard-socket
-@itemx --no-reuse-standard-socket
 @opindex use-standard-socket
 @opindex no-use-standard-socket
-@opindex no-reuse-standard-socket
 By enabling this option @command{gpg-agent} will listen on the socket
 named @file{S.gpg-agent}, located in the home directory, and not create
 a random socket below a temporary directory.  Tools connecting to
 @command{gpg-agent} should first try to connect to the socket given in
 environment variable @var{GPG_AGENT_INFO} and the fall back to this
 socket.  This option may not be used if the home directory is mounted as
-a remote file system.  If @option{--no-reuse-standard-socket} is used,
-@command{gpg-agent} will not try to reuse a socket which is already in
-use.  Note, that @option{--use-standard-socket} is the default on
-Windows systems.
+a remote file system.  Note, that @option{--use-standard-socket} is the
+default on Windows systems.
 
 
 @item --display @var{string}
index 69a7f10..b318ab8 100644 (file)
@@ -164,8 +164,9 @@ use @samp{--help} to get a list of supported operations.
 @table @gnupgtabopt
 @item --gen-key
 @opindex gen-key
-This command will only print an error message and direct the user to the
-@command{gpgsm-gencert.sh} script.
+This command allows the interactive creation of a certifcate signing
+request.  It is commonly used along with the @option{--output} option to
+save the created CSR into a file.
 
 @item --list-keys
 @itemx -k 
index b49d886..e3db0f8 100644 (file)
@@ -1,3 +1,12 @@
+2007-06-21  Werner Koch  <wk@g10code.com>
+
+       * main.h: Include util.h.
+
+       * call-agent.c (start_agent): Factored almost all code out to
+       ../common/asshelp.c.
+
+       * gpg.h (ctrl_t): Remove.  It is now declared in ../common/util.h.
+
 2007-06-20  Werner Koch  <wk@g10code.com>
 
        * misc.c (setsysinfo, trap_unaligned): Remove.  It is also in
index f2edfc0..57a45f6 100644 (file)
  * USA.
  */
 
-#if 0  /* let Emacs display a red warning */
-#error fixme: this shares a lot of code with the file in ../sm
-#endif
-
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -49,7 +45,6 @@
 #endif
 
 static assuan_context_t agent_ctx = NULL;
-static int force_pipe_server; 
 
 struct cipher_parm_s 
 {
@@ -79,107 +74,18 @@ struct genkey_parm_s
 static int
 start_agent (void)
 {
-  int rc = 0;
-  char *infostr, *p;
-  assuan_context_t ctx;
-
   if (agent_ctx)
-    return 0; /* fixme: We need a context for each thread or serialize
+    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 || !*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_syserror ();
-          log_error ("error flushing pending output: %s\n", strerror (errno));
-          return tmperr;
-        }
-
-      if (!opt.agent_program || !*opt.agent_program)
-        opt.agent_program = gnupg_module_name (GNUPG_MODULE_NAME_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, 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 (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
-        {
-          log_info (_("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", gpg_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 rc;
-
-  return send_pinentry_environment (agent_ctx, GPG_ERR_SOURCE_DEFAULT,
-                                    opt.display, opt.ttyname, opt.ttytype,
-                                    opt.lc_ctype, opt.lc_messages);
+  return start_new_gpg_agent (&agent_ctx,
+                              GPG_ERR_SOURCE_DEFAULT,
+                              opt.homedir,
+                              opt.agent_program,
+                              opt.display, opt.ttyname, opt.ttytype,
+                              opt.lc_ctype, opt.lc_messages,
+                              opt.verbose, DBG_ASSUAN,
+                              NULL, NULL);
 }
 
 
index 9e0c960..d47c58f 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -64,14 +64,6 @@ struct server_control_s
 {
   struct server_local_s *server_local;
 };
-typedef struct server_control_s *ctrl_t;
-
-
-
-
-/*-- server.c --*/
-int gpg_server (ctrl_t);
-
 
 
 
index 1860853..69e0d95 100644 (file)
 #define G10_MAIN_H
 
 #include "types.h"
-#include "../common/iobuf.h"
+#include "iobuf.h"
 #include "cipher.h"
 #include "keydb.h"
+#include "util.h"
+
 
 /* It could be argued that the default cipher should be 3DES rather
    than CAST5, and the default compression should be 0
@@ -300,6 +302,9 @@ void block_all_signals(void);
 void unblock_all_signals(void);
 
 
+/*-- server.c --*/
+int gpg_server (ctrl_t);
+
 #ifdef ENABLE_CARD_SUPPORT
 /*-- card-util.c --*/
 void change_pin (int no, int allow_admin);
index 1a1a80b..95ff963 100644 (file)
@@ -41,6 +41,7 @@
 #include "status.h"
 #include "i18n.h"
 #include "pkglue.h"
+#include "sysutils.h"
 #include "call-agent.h"
 
 
index 0f2b596..3db91a0 100644 (file)
@@ -1,3 +1,7 @@
+2007-06-21  Werner Koch  <wk@g10code.com>
+
+       * scdaemon.h (ctrl_t): Remove.  It is now declared in ../common/util.h.
+
 2007-06-18  Marcus Brinkmann  <marcus@g10code.de>
 
        * scdaemon.c (main): Percent escape output of --gpgconf-list.
index e1c5109..4086b85 100644 (file)
@@ -116,7 +116,6 @@ struct server_control_s
   } in_data;  
 };
 
-typedef struct server_control_s *ctrl_t;
 typedef struct app_ctx_s *app_t;
 
 /*-- scdaemon.c --*/
index 896b5c3..737a57d 100644 (file)
@@ -1,3 +1,15 @@
+2007-06-21  Werner Koch  <wk@g10code.com>
+
+       * certreqgen-ui.c: New.
+       * gpgsm.c (main): Let --gen-key call it.
+       * certreqgen.c (gpgsm_genkey): Add optional IN_STREAM arg and
+       adjusted caller.
+
+       * gpgsm.h (ctrl_t): Remove.  It is now declared in ../common/util.h.
+
+       * call-agent.c (start_agent): Factored almost all code out to
+       ../common/asshelp.c.
+
 2007-06-20  Werner Koch  <wk@g10code.com>
 
        * call-agent.c (start_agent) [W32]: Start the agent on the fly.
index 7e5c154..e560648 100644 (file)
@@ -50,6 +50,7 @@ gpgsm_SOURCES = \
        export.c \
        delete.c \
        certreqgen.c \
+       certreqgen-ui.c \
        qualified.c
 
 
index b30fe60..9483785 100644 (file)
 #include "asshelp.h"
 #include "keydb.h" /* fixme: Move this to import.c */
 #include "membuf.h"
-#include "exechelp.h"
 
 
 static assuan_context_t agent_ctx = NULL;
-static int force_pipe_server = 0;
+
 
 struct cipher_parm_s
 {
@@ -72,161 +71,25 @@ struct learn_parm_s
 static int
 start_agent (ctrl_t ctrl)
 {
-  int rc = 0;
-  char *infostr, *p;
-  assuan_context_t ctx;
-
   if (agent_ctx)
     return 0; /* fixme: We need a context for each thread or serialize
                  the access to the agent (which is suitable given that
                  the agent is not MT. */
 
-  infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
-  if (!infostr || !*infostr)
-    {
-      char *sockname;
-
-      /* First check whether we can connect at the standard
-         socket.  */
-      sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
-      rc = assuan_socket_connect (&ctx, sockname, 0);
-
-      if (rc)
-        {
-          /* With no success start a new server.  */
-          if (opt.verbose)
-            log_info (_("no running gpg-agent - starting one\n"));
-          
-          gpgsm_status (ctrl, STATUS_PROGRESS, "starting_agent ? 0 0");
-          
-          if (fflush (NULL))
-            {
-              gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
-              log_error ("error flushing pending output: %s\n",
-                         strerror (errno));
-              xfree (sockname);
-              return tmperr;
-            }
-          
-          if (!opt.agent_program || !*opt.agent_program)
-            opt.agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
-
-#ifdef HAVE_W32_SYSTEM
-          {
-            /* Under Windows we start the server in daemon mode.  This
-               is because the default is to use the standard socket
-               and thus there is no need for the GPG_AGENT_INFO
-               envvar.  This is possible as we don't have a real unix
-               domain socket but use a plain file and thus there is no
-               need to care about non-local file systems. */
-            const char *argv[3];
-
-            /* The --no-reuse-standard option makes sure that we don't
-               start a second instance of a agent in case another
-               process has started one in the meantime.  */
-            argv[0] = "--daemon";
-            argv[1] = "--no-reuse-standard-socket"; 
-            argv[2] = NULL;  
-
-            rc = gnupg_spawn_process_detached (opt.agent_program, argv, NULL);
-            if (rc)
-              log_debug ("failed to start agent `%s': %s\n",
-                         opt.agent_program, gpg_strerror (rc));
-            else
-              {
-                /* Give the agent some time to prepare itself. */
-                gnupg_sleep (3);
-                /* Now try again to connect the agent.  */
-                rc = assuan_socket_connect (&ctx, sockname, 0);
-              }
-          }
-#else /*!HAVE_W32_SYSTEM*/
-          {
-            const char *pgmname;
-            const char *argv[3];
-            int no_close_list[3];
-            int i;
-
-            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, argv,
-                                      no_close_list);
-          }
-#endif /*!HAVE_W32_SYSTEM*/
-        }
-      xfree (sockname);
-    }
-  else
-    {
-      int prot;
-      int pid;
-
-      infostr = xstrdup (infostr);
-      if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
-        {
-          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
-          xfree (infostr);
-          force_pipe_server = 1;
-          return start_agent (ctrl);
-        }
-      *p++ = 0;
-      pid = atoi (p);
-      while (*p && *p != PATHSEP_C)
-        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 (ctrl);
-        }
-
-      rc = assuan_socket_connect (&ctx, infostr, pid);
-      xfree (infostr);
-      if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
-        {
-          log_info (_("can't connect to the agent - trying fall back\n"));
-          force_pipe_server = 1;
-          return start_agent (ctrl);
-        }
-    }
 
-  if (rc)
-    {
-      log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
-      return gpg_error (GPG_ERR_NO_AGENT);
-    }
-  agent_ctx = ctx;
-
-  if (DBG_ASSUAN)
-    log_debug ("connection to agent established\n");
+  return start_new_gpg_agent (&agent_ctx,
+                              GPG_ERR_SOURCE_DEFAULT,
+                              opt.homedir,
+                              opt.agent_program,
+                              opt.display, opt.ttyname, opt.ttytype,
+                              opt.lc_ctype, opt.lc_messages,
+                              opt.verbose, DBG_ASSUAN,
+                              gpgsm_status2, ctrl);
 
-  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
-  if (rc)
-    return rc;
-
-  return send_pinentry_environment (agent_ctx, GPG_ERR_SOURCE_DEFAULT,
-                                    opt.display, opt.ttyname, opt.ttytype,
-                                    opt.lc_ctype, opt.lc_messages);
 }
 
 
+
 static int
 membuf_data_cb (void *opaque, const void *buffer, size_t length)
 {
diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c
new file mode 100644 (file)
index 0000000..738999f
--- /dev/null
@@ -0,0 +1,317 @@
+/* certreqgen-ui.c - Simple user interface for certreqgen.c
+ * Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#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 "gpgsm.h"
+#include <gcrypt.h>
+
+#include "i18n.h"
+#include "ttyio.h"
+#include "membuf.h"
+
+
+/* Prompt for lines and append them to MB.  */
+static void
+ask_mb_lines (membuf_t *mb, const char *prefix)
+{
+  char *answer = NULL;
+
+  do 
+    {
+      xfree (answer);
+      answer = tty_get ("> ");
+      tty_kill_prompt ();
+      trim_spaces (answer);
+      if (*answer)
+        {
+          put_membuf_str (mb, prefix);
+          put_membuf_str (mb, answer);
+          put_membuf (mb, "\n", 1);
+        }
+    }
+  while (*answer);
+  xfree (answer);
+}
+
+/* Helper to store stuff in a membuf.  */
+void
+store_key_value_lf (membuf_t *mb, const char *key, const char *value)
+{
+  put_membuf_str (mb, key);
+  put_membuf_str (mb, value);
+  put_membuf (mb, "\n", 1);
+}
+
+/* Helper tp store a membuf create by mb_ask_lines into MB.  Returns
+   -1 on error. */
+int
+store_mb_lines (membuf_t *mb, membuf_t *lines)
+{
+  char *p;
+
+  if (get_membuf_len (lines))
+    {
+      put_membuf (lines, "", 1);
+      p = get_membuf (lines, NULL);
+      if (!p)
+        return -1;
+      put_membuf_str (mb, p);
+      xfree (p);
+    }
+  return 0;
+}
+
+
+/* This function is used to create a certificate request from the
+   command line.  In the past the similar gpgsm-gencert.sh script has
+   been used for it; however that scripts requires a full Unix shell
+   and thus is not suitable for the Windows port.  So here is the
+   re-implementation.  */
+void
+gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
+{
+  gpg_error_t err;
+  char *answer;
+  int selection;
+  FILE *fp = NULL;
+  int method;
+  char *keytype;
+  char *keygrip = NULL;
+  unsigned int nbits;
+  int minbits = 1024;
+  int maxbits = 4096;
+  int defbits = 2048;
+  const char *keyusage;
+  char *subject_name;
+  membuf_t mb_email, mb_dns, mb_uri, mb_result;
+  char *result = NULL;
+  int i;
+  const char *s, *s2;
+
+  init_membuf (&mb_email, 100);
+  init_membuf (&mb_dns, 100);
+  init_membuf (&mb_uri, 100);
+  init_membuf (&mb_result, 512);
+
+  /* Get the type of the key.  */
+  tty_printf (_("Please select what kind of key you want:\n"));
+  tty_printf (_("   (%d) RSA\n"), 1 );
+  tty_printf (_("   (%d) Existing key\n"), 2 );
+  tty_printf (_("   (%d) Existing key from card\n"), 3 );
+
+  do
+    {
+      answer = tty_get (_("Your selection? "));
+      tty_kill_prompt ();
+      selection = *answer? atoi (answer): 1;
+      xfree (answer);
+    }
+  while (!(selection >= 1 && selection <= 3));
+  method = selection;
+
+  /* Get  size of the key.  */
+  if (method == 1)
+    {
+      keytype = xstrdup ("RSA");
+      for (;;)
+        {
+          answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
+          tty_kill_prompt ();
+          nbits = *answer? atoi (answer): defbits;
+          xfree (answer);
+          if (nbits < minbits || nbits > maxbits)
+            tty_printf(_("%s keysizes must be in the range %u-%u\n"),
+                         "RSA", minbits, maxbits);
+          else
+            break; /* Okay.  */
+        }
+      tty_printf (_("Requested keysize is %u bits\n"), nbits);
+      /* We round it up so that it better matches the word size.  */
+      if (( nbits % 64))
+        {
+          nbits = ((nbits + 63) / 64) * 64;
+          tty_printf (_("rounded up to %u bits\n"), nbits);
+        }
+    }
+  else if (method == 2)
+    {
+      tty_printf ("Not yet supported; "
+                  "use the gpgsm-gencert.sh script instead\n");
+      keytype = xstrdup ("RSA"); 
+      nbits = defbits; /* We need a dummy value.  */
+    }
+  else /* method == 3 */
+    {
+      tty_printf ("Not yet supported; "
+                  "use the gpgsm-gencert.sh script instead\n");
+      keytype = xstrdup ("card:foobar");
+      nbits = defbits; /* We need a dummy value.  */
+    }
+
+  /* Ask for the key usage.  */
+  tty_printf (_("Possible actions for a %s key:\n"), "RSA");
+  tty_printf (_("   (%d) sign, encrypt\n"), 1 );
+  tty_printf (_("   (%d) sign\n"), 2 );
+  tty_printf (_("   (%d) encrypt\n"), 3 );
+  do
+    {
+      answer = tty_get (_("Your selection? "));
+      tty_kill_prompt ();
+      selection = *answer? atoi (answer): 1;
+      xfree (answer);
+      switch (selection)
+        {
+        case 1: keyusage = "sign, encrypt"; break;
+        case 2: keyusage = "sign"; break;
+        case 3: keyusage = "encrypt"; break;
+        default: keyusage = NULL; break;
+        }
+    }
+  while (!keyusage);
+
+  /* Get the subject name.  */
+  answer = NULL;
+  do
+    {
+      size_t erroff, errlen;
+
+      xfree (answer);
+      answer = tty_get (_("Enter the X.509 subject name: "));
+      tty_kill_prompt ();
+      trim_spaces (answer);
+      if (!*answer)
+        tty_printf (_("No subject name given\n"));
+      else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
+        {
+          if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
+            tty_printf (_("Invalid subject name label `%.*s'\n"),
+                        (int)errlen, answer+erroff);
+          else
+            {
+              /* TRANSLATORS: The 22 in the second string is the
+                 length of the first string up to the "%s".  Please
+                 adjust it do the length of your translation.  The
+                 second string is merely passed to atoi so you can
+                 drop everything after the number.  */
+              tty_printf (_("Invalid subject name `%s'\n"), answer);
+              tty_printf ("%*s^\n",
+                          atoi (_("22 translator: see "
+                                  "certreg-ui.c:gpgsm_gencertreq_tty"))
+                          + (int)erroff, "");
+            }
+          *answer = 0;
+        }
+    }
+  while (!*answer);
+  subject_name = answer;
+  answer = NULL;
+
+  /* Get the email addresses. */
+  tty_printf (_("Enter email addresses"));
+  tty_printf (_(" (end with an empty line):\n"));
+  ask_mb_lines (&mb_email, "Name-Email: ");
+
+  /* DNS names.  */
+  tty_printf (_("Enter DNS names"));
+  tty_printf (_(" (optional; end with an empty line):\n"));
+  ask_mb_lines (&mb_email, "Name-DNS: ");
+
+  /* URIs.  */
+  tty_printf (_("Enter URIs"));
+  tty_printf (_(" (optional; end with an empty line):\n"));
+  ask_mb_lines (&mb_email, "Name-URI: ");
+
+
+  /* Put it all together.  */
+  store_key_value_lf (&mb_result, "Key-Type: ", keytype);
+  {
+    char numbuf[30];
+    snprintf (numbuf, sizeof numbuf, "%u", nbits);
+    store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
+  }
+  store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
+  store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
+  if (keygrip)
+    store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
+  if (store_mb_lines (&mb_result, &mb_email))
+    goto mem_error;
+  if (store_mb_lines (&mb_result, &mb_dns))
+    goto mem_error;
+  if (store_mb_lines (&mb_result, &mb_uri))
+    goto mem_error;
+  put_membuf (&mb_result, "", 1);
+  result = get_membuf (&mb_result, NULL);
+  if (!result)
+    goto mem_error;
+
+  tty_printf (_("Parameters to be used for the certificate request:\n"));
+  for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
+    tty_printf ("    %.*s\n", (int)(s2-s), s);
+  tty_printf ("\n");
+
+
+  if (!tty_get_answer_is_yes ("Really create request? (y/N) "))
+     goto leave;
+
+  /* Now create a parameter file and generate the key.  */
+  fp = tmpfile ();
+  if (!fp)
+    {
+      log_error (_("error creating temporary file: %s\n"), strerror (errno));
+      goto leave;
+    }
+  fputs (result, fp);
+  rewind (fp);
+  tty_printf (_("Now creating certificate request.  "
+                "This may take a while ...\n"));
+  {
+    int save_pem = ctrl->create_pem;
+    ctrl->create_pem = 1; /* Force creation of PEM. */
+    err = gpgsm_genkey (ctrl, -1, fp, output_fp);
+    ctrl->create_pem = save_pem;
+  }
+  if (!err)
+    tty_printf (_("Ready.  You should now send this request to your CA.\n"));
+
+
+  goto leave;
+ mem_error:
+  log_error (_("resource problem: out or core\n"));
+ leave:
+  if (fp)
+    fclose (fp);
+  xfree (keytype);         
+  xfree (subject_name);
+  xfree (keygrip);
+  xfree (get_membuf (&mb_email, NULL));
+  xfree (get_membuf (&mb_dns, NULL));
+  xfree (get_membuf (&mb_uri, NULL));
+  xfree (get_membuf (&mb_result, NULL));
+  xfree (result);
+}
index 043e218..4ffd836 100644 (file)
@@ -831,17 +831,20 @@ create_request (ctrl_t ctrl,
 
 
 \f
-/* Create a new key by reading the parameters from in_fd.  Multiple
-   keys may be created */
+/* Create a new key by reading the parameters from in_fd or in_stream.
+   Multiple keys may be created */
 int
-gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp)
+gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *in_stream, FILE *out_fp)
 {
   int rc;
   FILE *in_fp;
   Base64Context b64writer = NULL;
   ksba_writer_t writer;
 
-  in_fp = fdopen (dup (in_fd), "rb");
+  if (in_stream)
+    in_fp = in_stream;
+  else
+    in_fp = fdopen (dup (in_fd), "rb");
   if (!in_fp)
     {
       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
@@ -877,7 +880,8 @@ gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp)
 
  leave:
   gpgsm_destroy_writer (b64writer);
-  fclose (in_fp);
+  if (!in_stream)
+    fclose (in_fp);
   return rc;
 }
 
index b6a3e69..ee6cf08 100644 (file)
@@ -1590,12 +1590,15 @@ main ( int argc, char **argv)
 
 
     case aKeygen: /* Generate a key; well kind of. */
-      log_error 
-        (_("key generation is not available from the commandline\n"));
-      log_info (_("please use the script \"%s\" to generate a new key\n"),
-                "gpgsm-gencert.sh");
+      {
+        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        gpgsm_gencertreq_tty (&ctrl, fp);
+        if (fp != stdout)
+          fclose (fp);
+      }
       break;
 
+
     case aImport:
       gpgsm_import_files (&ctrl, argc, argv, open_read);
       break;
index 727b1cf..62b106b 100644 (file)
@@ -167,7 +167,6 @@ struct server_control_s
                          signer) */
   int use_ocsp;       /* Set to true if OCSP should be used. */
 };
-typedef struct server_control_s *ctrl_t;
 
 
 /* Data structure used in base64.c. */
@@ -317,7 +316,11 @@ int gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int in_fd, FILE *out_fp);
 int gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp);
 
 /*-- certreqgen.c --*/
-int gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp);
+int gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *in_stream, FILE *out_fp);
+
+/*-- certreqgen-ui.c --*/
+void gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *out_fp);
+
 
 /*-- qualified.c --*/
 gpg_error_t gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert,
index 278f4ec..2774979 100644 (file)
@@ -865,7 +865,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
   out_fp = fdopen ( dup(out_fd), "w");
   if (!out_fp)
     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
-  rc = gpgsm_genkey (ctrl, inp_fd, out_fp);
+  rc = gpgsm_genkey (ctrl, inp_fd, NULL, out_fp);
   fclose (out_fp);
 
   /* close and reset the fds */