summaryrefslogtreecommitdiffstats
path: root/common/asshelp.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2007-06-21 20:44:48 +0200
committerWerner Koch <wk@gnupg.org>2007-06-21 20:44:48 +0200
commit0b66f30d66fadbfd1a949edbe765043b06c5931b (patch)
treee2e33a51151de2deac0d4e43cd7bc38429fe2965 /common/asshelp.c
parent[w32] gpg-agent is now started automagically by gpgsm. (diff)
downloadgnupg2-0b66f30d66fadbfd1a949edbe765043b06c5931b.tar.xz
gnupg2-0b66f30d66fadbfd1a949edbe765043b06c5931b.zip
Implemented the --gen-key command as we can't use the gpgsm-gencert.sh under Windows.
Diffstat (limited to 'common/asshelp.c')
-rw-r--r--common/asshelp.c184
1 files changed, 183 insertions, 1 deletions
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;
+}
+