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 /common/asshelp.c | |
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.
Diffstat (limited to 'common/asshelp.c')
-rw-r--r-- | common/asshelp.c | 184 |
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; +} + |