diff options
author | Werner Koch <wk@gnupg.org> | 2007-06-21 20:44:48 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2007-06-21 20:44:48 +0200 |
commit | 0b66f30d66fadbfd1a949edbe765043b06c5931b (patch) | |
tree | e2e33a51151de2deac0d4e43cd7bc38429fe2965 | |
parent | [w32] gpg-agent is now started automagically by gpgsm. (diff) | |
download | gnupg2-0b66f30d66fadbfd1a949edbe765043b06c5931b.tar.xz gnupg2-0b66f30d66fadbfd1a949edbe765043b06c5931b.zip |
Implemented the --gen-key command as we can't use the gpgsm-gencert.sh under Windows.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | agent/ChangeLog | 9 | ||||
-rw-r--r-- | agent/agent.h | 2 | ||||
-rw-r--r-- | agent/gpg-agent.c | 69 | ||||
-rw-r--r-- | common/ChangeLog | 14 | ||||
-rw-r--r-- | common/asshelp.c | 184 | ||||
-rw-r--r-- | common/asshelp.h | 16 | ||||
-rw-r--r-- | common/exechelp.c | 2 | ||||
-rw-r--r-- | common/membuf.c | 9 | ||||
-rw-r--r-- | common/membuf.h | 3 | ||||
-rw-r--r-- | common/ttyio.c | 23 | ||||
-rw-r--r-- | common/ttyio.h | 3 | ||||
-rw-r--r-- | common/util.h | 6 | ||||
-rw-r--r-- | doc/ChangeLog | 5 | ||||
-rw-r--r-- | doc/glossary.texi | 5 | ||||
-rw-r--r-- | doc/gpg-agent.texi | 8 | ||||
-rw-r--r-- | doc/gpgsm.texi | 5 | ||||
-rw-r--r-- | g10/ChangeLog | 9 | ||||
-rw-r--r-- | g10/call-agent.c | 112 | ||||
-rw-r--r-- | g10/gpg.h | 8 | ||||
-rw-r--r-- | g10/main.h | 7 | ||||
-rw-r--r-- | g10/sign.c | 1 | ||||
-rw-r--r-- | scd/ChangeLog | 4 | ||||
-rw-r--r-- | scd/scdaemon.h | 1 | ||||
-rw-r--r-- | sm/ChangeLog | 12 | ||||
-rw-r--r-- | sm/Makefile.am | 1 | ||||
-rw-r--r-- | sm/call-agent.c | 157 | ||||
-rw-r--r-- | sm/certreqgen-ui.c | 317 | ||||
-rw-r--r-- | sm/certreqgen.c | 14 | ||||
-rw-r--r-- | sm/gpgsm.c | 11 | ||||
-rw-r--r-- | sm/gpgsm.h | 7 | ||||
-rw-r--r-- | sm/server.c | 2 |
33 files changed, 714 insertions, 317 deletions
@@ -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) ------------------------------------------------ @@ -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 diff --git a/agent/ChangeLog b/agent/ChangeLog index 19564556e..653bcd032 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -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 diff --git a/agent/agent.h b/agent/agent.h index cb1cca084..690a86df5 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -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 { diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index a0646925c..360870f27 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -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); diff --git a/common/ChangeLog b/common/ChangeLog index 3f8fa41c4..e80e70359 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -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. diff --git a/common/asshelp.c b/common/asshelp.c index 54d7224d8..024128042 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -29,8 +29,11 @@ #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; +} + diff --git a/common/asshelp.h b/common/asshelp.h index 9f4b5806b..adf81f9b7 100644 --- a/common/asshelp.h +++ b/common/asshelp.h @@ -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*/ diff --git a/common/exechelp.c b/common/exechelp.c index d0be84047..c488e291a 100644 --- a/common/exechelp.c +++ b/common/exechelp.c @@ -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. */ diff --git a/common/membuf.c b/common/membuf.c index 51014592b..eb436c466 100644 --- a/common/membuf.c +++ b/common/membuf.c @@ -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) { diff --git a/common/membuf.h b/common/membuf.h index f9c08a400..906ae156c 100644 --- a/common/membuf.h +++ b/common/membuf.h @@ -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); diff --git a/common/ttyio.c b/common/ttyio.c index 831ad9048..98a4614fe 100644 --- a/common/ttyio.c +++ b/common/ttyio.c @@ -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 ) { diff --git a/common/ttyio.h b/common/ttyio.h index d93906eab..eed6b0910 100644 --- a/common/ttyio.h +++ b/common/ttyio.h @@ -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); diff --git a/common/util.h b/common/util.h index 42df1274f..39858216f 100644 --- a/common/util.h +++ b/common/util.h @@ -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*/ diff --git a/doc/ChangeLog b/doc/ChangeLog index a87680b2b..27546e08f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -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. diff --git a/doc/glossary.texi b/doc/glossary.texi index 6eede19d2..22bd7adc5 100644 --- a/doc/glossary.texi +++ b/doc/glossary.texi @@ -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. diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index 85ce1acd4..e9ef3a9e9 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -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} diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 69a7f10d7..b318ab877 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -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 diff --git a/g10/ChangeLog b/g10/ChangeLog index b49d8868b..e3db0f80f 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -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 diff --git a/g10/call-agent.c b/g10/call-agent.c index f2edfc0f4..57a45f6fb 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -19,10 +19,6 @@ * 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); } @@ -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); - diff --git a/g10/main.h b/g10/main.h index 1860853da..69e0d95f5 100644 --- a/g10/main.h +++ b/g10/main.h @@ -23,9 +23,11 @@ #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); diff --git a/g10/sign.c b/g10/sign.c index 1a1a80bc6..95ff96373 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -41,6 +41,7 @@ #include "status.h" #include "i18n.h" #include "pkglue.h" +#include "sysutils.h" #include "call-agent.h" diff --git a/scd/ChangeLog b/scd/ChangeLog index 0f2b59696..3db91a0f7 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -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. diff --git a/scd/scdaemon.h b/scd/scdaemon.h index e1c5109d5..4086b854c 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -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 --*/ diff --git a/sm/ChangeLog b/sm/ChangeLog index 896b5c368..737a57d0c 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -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. diff --git a/sm/Makefile.am b/sm/Makefile.am index 7e5c154ac..e56064812 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -50,6 +50,7 @@ gpgsm_SOURCES = \ export.c \ delete.c \ certreqgen.c \ + certreqgen-ui.c \ qualified.c diff --git a/sm/call-agent.c b/sm/call-agent.c index b30fe60df..9483785cc 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -38,11 +38,10 @@ #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 index 000000000..738999ff8 --- /dev/null +++ b/sm/certreqgen-ui.c @@ -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); +} diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 043e218c4..4ffd8363e 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -831,17 +831,20 @@ create_request (ctrl_t ctrl, -/* 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; } diff --git a/sm/gpgsm.c b/sm/gpgsm.c index b6a3e69c2..ee6cf08cd 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -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; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 727b1cf98..62b106bfc 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -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, diff --git a/sm/server.c b/sm/server.c index 278f4ecbf..27749799c 100644 --- a/sm/server.c +++ b/sm/server.c @@ -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 */ |