Auto-start dirmngr.

This commit is contained in:
Werner Koch 2010-08-16 11:03:43 +00:00
parent c3be3aef40
commit 7e752a4208
11 changed files with 230 additions and 183 deletions

6
NEWS
View File

@ -29,7 +29,11 @@ Noteworthy changes in version 2.1.x (under development)
option --enable-standard-socket may now be used to use this feature
by default.
* Dirmngr is now a part of this package.
* Dirmngr is now a part of this package. Dirmngr is now also
expected to run as a system service and the configuraion
directories are changed to the gnupg name space.
* Given sufficient permissions Dirmngr is started automagically.
Noteworthy changes in version 2.0.13 (2009-09-04)

View File

@ -1,3 +1,11 @@
2010-08-16 Werner Koch <wk@g10code.com>
* asshelp.c (lock_agent_t): Rename to lock_spawn_t.
(lock_agent_spawning, unlock_agent_spawning): Factor code out to ...
(lock_spawning, unlock_spawning): .. new.
(start_new_gpg_agent): Make more use of ERRSOURCE.
(start_new_dirmngr): New.
2010-08-13 Werner Koch <wk@g10code.com>
* Makefile.am (audit-events.h, status-codes.h): Fix srcdir problem

View File

@ -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;
}

View File

@ -49,5 +49,17 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
/* This function is used to connect to the dirmngr. On some platforms
the function is able starts a dirmngr process if needed. */
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);
#endif /*GNUPG_COMMON_ASSHELP_H*/

View File

@ -194,7 +194,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_i (oMaxReplies, "max-replies",
N_("|N|do not return more than N items in one query")),
ARGPARSE_s_s (oSocketName, "socket-name", N_("|FILE|listen on socket FILE")),
ARGPARSE_s_s (oSocketName, "socket-name", "@"), /* Only for debugging. */
ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/
ARGPARSE_p_u (oDebug, "debug", "@"),
@ -897,6 +897,7 @@ main (int argc, char **argv)
if (cmd == aServer)
{
/* Note that this server mode is maily useful for debugging. */
if (argc)
wrong_args ("--server");
@ -1002,6 +1003,9 @@ main (int argc, char **argv)
es_fflush (NULL);
/* Note: We keep the dirmngr_info output only for the sake of
existing scripts which might use this to detect a successful
start of the dirmngr. */
#ifdef HAVE_W32_SYSTEM
pid = getpid ();
printf ("set DIRMNGR_INFO=%s;%lu;1\n", socket_name, (ulong) pid);
@ -1032,7 +1036,7 @@ main (int argc, char **argv)
dirmngr_exit (1);
}
/* Print the environment string, so that the caller can use
shell's eval to set it */
shell's eval to set it. But see above. */
if (csh_style)
{
*strchr (infostr, '=') = ' ';

View File

@ -469,7 +469,7 @@ dirmngr --daemon
@end example
Please ignore the output; it is not needed anymore. Check the log file
to see whether all trusted root certificates have benn loaded correctly.
to see whether all trusted root certificates have been loaded correctly.
@c
@ -519,15 +519,8 @@ This prints some caching statistics to the log file.
@section Examples
The way to start the dirmngr in the foreground (as done by tools if no
dirmngr is running in the background) is to use:
@example
dirmngr --server -v
@end example
If a dirmngr is supposed to be used as a system wide daemon, it should
be started like:
Dirmngr is supposed to be used as a system wide daemon, it should be
started like:
@example
dirmngr --daemon
@ -539,6 +532,14 @@ socket for client requests. It does also print information about the
socket used but they are only for compatibilty reasons with old GnuPG
versions and may be ignored.
For debugging purposes it is also possible to start Dirmngr in the
foreground:
@example
dirmngr --server -v
@end example
@c
@c Assuan Protocol

View File

@ -1,3 +1,16 @@
2010-08-16 Werner Koch <wk@g10code.com>
* call-dirmngr.c (start_dirmngr_ext): Use new start_new_dirmngr
function.
* gpgsm.c: Mark option --prefer-system-dirmngr obsolete.
(main): Enable dirmngr by default.
* gpgsm.h (struct opt): Remove field PREFER_SYSTEM_DIRMNGR.
* server.c (gpgsm_server): Use dirmngr_socket_name instead of the
envvar for the hello line info.
2010-06-21 Werner Koch <wk@g10code.com>
* minip12.c (p12_build): Change arg CERT to const void ptr.

View File

@ -1,5 +1,6 @@
/* call-dirmngr.c - communication with the dromngr
* Copyright (C) 2002, 2003, 2005, 2007, 2008 Free Software Foundation, Inc.
/* call-dirmngr.c - Communication with the dirmngr
* Copyright (C) 2002, 2003, 2005, 2007, 2008,
* 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -33,6 +34,7 @@
#include "i18n.h"
#include "keydb.h"
#include "asshelp.h"
struct membuf {
@ -52,8 +54,6 @@ static assuan_context_t dirmngr2_ctx = NULL;
static int dirmngr_ctx_locked;
static int dirmngr2_ctx_locked;
static int force_pipe_server = 0;
struct inq_certificate_parm_s {
ctrl_t ctrl;
assuan_context_t ctx;
@ -184,15 +184,12 @@ prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
/* Try to connect to the agent via socket or fork it off and work by
pipes. Handle the server's initial greeting */
static int
/* Return a new assuan context for a Dirmngr connection. */
static gpg_error_t
start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
{
int rc;
char *infostr, *p;
assuan_context_t ctx = NULL;
int try_default = 0;
gpg_error_t err;
assuan_context_t ctx;
if (opt.disable_dirmngr)
return gpg_error (GPG_ERR_NO_DIRMNGR);
@ -203,129 +200,15 @@ start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
/* Note: if you change this to multiple connections, you also need
to take care of the implicit option sending caching. */
#ifdef HAVE_W32_SYSTEM
infostr = NULL;
opt.prefer_system_dirmngr = 1;
#else
infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
#endif /*HAVE_W32_SYSTEM*/
if (infostr && !*infostr)
infostr = NULL;
else if (infostr)
infostr = xstrdup (infostr);
err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT,
opt.homedir, opt.dirmngr_program,
opt.verbose, DBG_ASSUAN,
gpgsm_status2, ctrl);
prepare_dirmngr (ctrl, ctx, err);
if (err)
return err;
if (opt.prefer_system_dirmngr && !force_pipe_server && !infostr)
{
infostr = xstrdup (dirmngr_socket_name ());
try_default = 1;
}
rc = assuan_new (&ctx);
if (rc)
{
log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
return rc;
}
if (!infostr)
{
const char *pgmname;
const char *argv[3];
int no_close_list[3];
int i;
if (!opt.dirmngr_program || !*opt.dirmngr_program)
opt.dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
pgmname = opt.dirmngr_program;
else
pgmname++;
if (opt.verbose)
log_info (_("no running dirmngr - starting `%s'\n"),
opt.dirmngr_program);
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));
return tmperr;
}
argv[0] = pgmname;
argv[1] = "--server";
argv[2] = NULL;
i=0;
if (log_get_fd () != -1)
no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
no_close_list[i] = -1;
/* connect to the agent and perform initial handshaking */
rc = assuan_pipe_connect (ctx, opt.dirmngr_program, argv,
no_close_list, NULL, NULL, 0);
}
else
{
int prot;
int pid;
if (!try_default)
{
if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
{
log_error (_("malformed DIRMNGR_INFO environment variable\n"));
xfree (infostr);
force_pipe_server = 1;
return start_dirmngr_ext (ctrl, ctx_r);
}
*p++ = 0;
pid = atoi (p);
while (*p && *p != PATHSEP_C)
p++;
prot = *p? atoi (p+1) : 0;
if (prot != 1)
{
log_error (_("dirmngr protocol version %d is not supported\n"),
prot);
xfree (infostr);
force_pipe_server = 1;
return start_dirmngr_ext (ctrl, ctx_r);
}
}
else
pid = -1;
rc = assuan_socket_connect (ctx, infostr, pid, 0);
#ifdef HAVE_W32_SYSTEM
if (rc)
log_debug ("connecting dirmngr at `%s' failed\n", infostr);
#endif
xfree (infostr);
#ifndef HAVE_W32_SYSTEM
if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
{
log_info (_("can't connect to the dirmngr - trying fall back\n"));
force_pipe_server = 1;
return start_dirmngr_ext (ctrl, ctx_r);
}
#endif /*!HAVE_W32_SYSTEM*/
}
prepare_dirmngr (ctrl, ctx, rc);
if (rc)
{
assuan_release (ctx);
log_error ("can't connect to the dirmngr: %s\n", gpg_strerror (rc));
return gpg_error (GPG_ERR_NO_DIRMNGR);
}
*ctx_r = ctx;
if (DBG_ASSUAN)
log_debug ("connection to dirmngr established\n");
return 0;
}

View File

@ -240,8 +240,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
ARGPARSE_s_n (oPreferSystemDirmngr,"prefer-system-dirmngr",
N_("use system's dirmngr if available")),
ARGPARSE_s_n (oPreferSystemDirmngr,"prefer-system-dirmngr", "@"),
ARGPARSE_s_n (oDisableCRLChecks, "disable-crl-checks",
N_("never consult a CRL")),
@ -941,10 +940,6 @@ main ( int argc, char **argv)
opt.homedir = default_homedir ();
#ifdef HAVE_W32CE_SYSTEM
opt.disable_dirmngr = 1;
opt.no_crl_check = 1;
#endif
/* First check whether we have a config file on the commandline */
orig_argc = argc;
@ -1280,7 +1275,7 @@ main ( int argc, char **argv)
case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
case oDisableDirmngr: opt.disable_dirmngr = 1; break;
case oPreferSystemDirmngr: opt.prefer_system_dirmngr = 1; break;
case oPreferSystemDirmngr: /* Obsolete */; break;
case oProtectToolProgram:
opt.protect_tool_program = pargs.r.ret_str;
break;
@ -1659,9 +1654,6 @@ main ( int argc, char **argv)
printf ("disable-policy-checks:%lu:\n", GC_OPT_FLAG_NONE);
printf ("auto-issuer-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE);
printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
#ifndef HAVE_W32_SYSTEM
printf ("prefer-system-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
#endif
printf ("cipher-algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
DEFAULT_CIPHER_ALGO);
printf ("p12-charset:%lu:\n", GC_OPT_FLAG_DEFAULT);

View File

@ -69,7 +69,6 @@ struct
char *lc_messages;
const char *dirmngr_program;
int prefer_system_dirmngr; /* Prefer using a system wide drimngr. */
int disable_dirmngr; /* Do not do any dirmngr calls. */
const char *protect_tool_program;
char *outfile; /* name of output file */

View File

@ -1293,7 +1293,6 @@ gpgsm_server (certlist_t default_recplist)
{
char *tmp = NULL;
const char *s1 = getenv ("GPG_AGENT_INFO");
const char *s2 = getenv ("DIRMNGR_INFO");
if (asprintf (&tmp,
"Home: %s\n"
@ -1304,7 +1303,7 @@ gpgsm_server (certlist_t default_recplist)
opt.homedir,
opt.config_filename,
s1?s1:"[not set]",
s2?s2:"[not set]",
dirmngr_socket_name (),
hello) > 0)
{
assuan_set_hello_line (ctx, tmp);