aboutsummaryrefslogtreecommitdiffstats
path: root/common/asshelp.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/asshelp.c')
-rw-r--r--common/asshelp.c182
1 files changed, 157 insertions, 25 deletions
diff --git a/common/asshelp.c b/common/asshelp.c
index 882c15479..b98825bd3 100644
--- a/common/asshelp.c
+++ b/common/asshelp.c
@@ -37,9 +37,9 @@
/* The type we use for lock_agent_spawning. */
#ifdef HAVE_W32_SYSTEM
-# define lock_agent_t HANDLE
+# define lock_spawn_t HANDLE
#else
-# define lock_agent_t dotlock_t
+# define lock_spawn_t dotlock_t
#endif
@@ -216,21 +216,26 @@ send_pinentry_environment (assuan_context_t ctx,
}
-/* Lock the agent spawning process. The caller needs to provide the
- address of a variable to store the lock information. */
+/* Lock a spawning process. The caller needs to provide the address
+ of a variable to store the lock information and the name or the
+ process. */
static gpg_error_t
-lock_agent_spawning (lock_agent_t *lock, const char *homedir)
+lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name)
{
#ifdef HAVE_W32_SYSTEM
int waitrc;
-
+
(void)homedir; /* Not required. */
- *lock = CreateMutexW (NULL, FALSE, L"GnuPG_spawn_agent_sentinel");
+ *lock = CreateMutexW
+ (NULL, FALSE,
+ !strcmp (name, "agent")? L"GnuPG_spawn_agent_sentinel":
+ !strcmp (name, "dirmngr")? L"GnuPG_spawn_dirmngr_sentinel":
+ /* */ L"GnuPG_spawn_unknown_sentinel");
if (!*lock)
{
- log_error ("failed to create the spawn_agent mutex: %s\n",
- w32_strerror (-1));
+ log_error ("failed to create the spawn_%s mutex: %s\n",
+ name, w32_strerror (-1));
return gpg_error (GPG_ERR_GENERAL);
}
@@ -239,17 +244,22 @@ lock_agent_spawning (lock_agent_t *lock, const char *homedir)
return 0;
if (waitrc == WAIT_TIMEOUT)
- log_info ("error waiting for the spawn_agent mutex: timeout\n");
+ log_info ("error waiting for the spawn_%s mutex: timeout\n", name);
else
- log_info ("error waiting for the spawn_agent mutex: "
- "(code=%d) %s\n", waitrc, w32_strerror (-1));
+ log_info ("error waiting for the spawn_%s mutex: (code=%d) %s\n",
+ name, waitrc, w32_strerror (-1));
return gpg_error (GPG_ERR_GENERAL);
#else /*!HAVE_W32_SYSTEM*/
char *fname;
*lock = NULL;
- fname = make_filename (homedir, "gnupg_spawn_agent_sentinel", NULL);
+ fname = make_filename
+ (homedir,
+ !strcmp (name, "agent")? "gnupg_spawn_agent_sentinel":
+ !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
+ /* */ "gnupg_spawn_unknown_sentinel",
+ NULL);
if (!fname)
return gpg_error_from_syserror ();
@@ -270,22 +280,38 @@ lock_agent_spawning (lock_agent_t *lock, const char *homedir)
/* Unlock the spawning process. */
static void
-unlock_agent_spawning (lock_agent_t *lock)
+unlock_spawning (lock_spawn_t *lock, const char *name)
{
if (*lock)
{
#ifdef HAVE_W32_SYSTEM
if (!ReleaseMutex (*lock))
- log_error ("failed to release the spawn_agent mutex: %s\n",
- w32_strerror (-1));
+ log_error ("failed to release the spawn_%s mutex: %s\n",
+ name, w32_strerror (-1));
CloseHandle (*lock);
#else /*!HAVE_W32_SYSTEM*/
+ (void)name;
destroy_dotlock (*lock);
#endif /*!HAVE_W32_SYSTEM*/
*lock = NULL;
}
}
+/* Lock the agent spawning process. The caller needs to provide the
+ address of a variable to store the lock information. */
+static gpg_error_t
+lock_agent_spawning (lock_spawn_t *lock, const char *homedir)
+{
+ return lock_spawning (lock, homedir, "agent");
+}
+
+
+static void
+unlock_agent_spawning (lock_spawn_t *lock)
+{
+ unlock_spawning (lock, "agent");
+}
+
/* 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
@@ -336,8 +362,12 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
if (err)
{
/* With no success start a new server. */
+ if (!agent_program || !*agent_program)
+ agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
+
if (verbose)
- log_info (_("no running gpg-agent - starting one\n"));
+ log_info (_("no running %s - starting `%s'\n"),
+ "gpg-agent", agent_program);
if (status_cb)
status_cb (status_cb_arg, STATUS_PROGRESS,
@@ -345,7 +375,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
if (fflush (NULL))
{
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
+ gpg_error_t tmperr = gpg_err_make (errsource,
+ gpg_err_code_from_syserror ());
log_error ("error flushing pending output: %s\n",
strerror (errno));
xfree (sockname);
@@ -353,9 +384,6 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
return tmperr;
}
- if (!agent_program || !*agent_program)
- agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
-
argv[0] = "--use-standard-socket-p";
argv[1] = NULL;
err = gnupg_spawn_process_fd (agent_program, argv, -1, -1, -1, &pid);
@@ -376,7 +404,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
standard socket, an environment variable is not
required and thus we we can savely start the agent
here. */
- lock_agent_t lock;
+ lock_spawn_t lock;
argv[0] = "--daemon";
argv[1] = "--use-standard-socket";
@@ -394,8 +422,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
int i;
if (verbose)
- log_info (_("waiting %d seconds for the agent "
- "to come up\n"), 5);
+ log_info (_("waiting %d seconds for the %s "
+ "to come up\n"), 5, "agent" );
for (i=0; i < 5; i++)
{
gnupg_sleep (1);
@@ -481,7 +509,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
{
log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
assuan_release (ctx);
- return gpg_error (GPG_ERR_NO_AGENT);
+ return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
}
if (debug)
@@ -503,3 +531,107 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
return 0;
}
+
+/* Try to connect to the dirmngr via a socket. On platforms
+ supporting it, start it up if needed. Returns a new assuan context
+ at R_CTX or an error code. */
+gpg_error_t
+start_new_dirmngr (assuan_context_t *r_ctx,
+ gpg_err_source_t errsource,
+ const char *homedir,
+ const char *dirmngr_program,
+ int verbose, int debug,
+ gpg_error_t (*status_cb)(ctrl_t, int, ...),
+ ctrl_t status_cb_arg)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+ const char *sockname;
+ lock_spawn_t lock;
+
+ *r_ctx = NULL;
+
+ err = assuan_new (&ctx);
+ if (err)
+ {
+ log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ sockname = dirmngr_socket_name ();
+ err = assuan_socket_connect (ctx, sockname, 0, 0);
+ if (err)
+ {
+ const char *argv[2];
+
+ /* With no success try start a new Dirmngr. On most systems
+ this will fail because the Dirmngr is expected to be a system
+ service. However on Wince we don't distinguish users and
+ thus we can start it. A future extension might be to use the
+ userv system to start the Dirmngr as a system service. */
+ if (!dirmngr_program || !*dirmngr_program)
+ dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
+
+ if (verbose)
+ log_info (_("no running %s - starting `%s'\n"),
+ "dirmngr", dirmngr_program);
+
+ if (status_cb)
+ status_cb (status_cb_arg, STATUS_PROGRESS,
+ "starting_dirmngr ? 0 0", NULL);
+
+ if (fflush (NULL))
+ {
+ gpg_error_t tmperr = gpg_err_make (errsource,
+ gpg_err_code_from_syserror ());
+ log_error ("error flushing pending output: %s\n",
+ strerror (errno));
+ assuan_release (ctx);
+ return tmperr;
+ }
+
+ argv[0] = "--daemon";
+ argv[1] = NULL;
+
+ if (!(err = lock_spawning (&lock, homedir, "dirmngr"))
+ && assuan_socket_connect (ctx, sockname, 0, 0))
+ {
+ err = gnupg_spawn_process_detached (dirmngr_program, argv,NULL);
+ if (err)
+ log_error ("failed to start the dirmngr `%s': %s\n",
+ dirmngr_program, gpg_strerror (err));
+ else
+ {
+ int i;
+
+ if (verbose)
+ log_info (_("waiting %d seconds for the %s to come up\n"),
+ 5, "dirmngr" );
+ for (i=0; i < 5; i++)
+ {
+ gnupg_sleep (1);
+ err = assuan_socket_connect (ctx, sockname, 0, 0);
+ if (!err)
+ break;
+ }
+ }
+ }
+
+ unlock_spawning (&lock, "dirmngr");
+ }
+
+ if (err)
+ {
+ log_error ("connecting dirmngr at `%s' failed: %s\n",
+ sockname, gpg_strerror (err));
+ assuan_release (ctx);
+ return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
+ }
+
+ if (debug)
+ log_debug ("connection to the dirmngr established\n");
+
+ *r_ctx = ctx;
+ return 0;
+}
+