diff --git a/NEWS b/NEWS index 200e1aa2b..0feecb4e1 100644 --- a/NEWS +++ b/NEWS @@ -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) diff --git a/common/ChangeLog b/common/ChangeLog index 281dd64c6..070305370 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,11 @@ +2010-08-16 Werner Koch + + * 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 * Makefile.am (audit-events.h, status-codes.h): Fix srcdir problem 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; +} + diff --git a/common/asshelp.h b/common/asshelp.h index 3c961fef8..0eb6553f9 100644 --- a/common/asshelp.h +++ b/common/asshelp.h @@ -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*/ diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 771a58642..ed6259a29 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -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, '=') = ' '; diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi index 34450474c..e6264878a 100644 --- a/doc/dirmngr.texi +++ b/doc/dirmngr.texi @@ -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 diff --git a/sm/ChangeLog b/sm/ChangeLog index 02f3347d2..d4157c2ca 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,16 @@ +2010-08-16 Werner Koch + + * 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 * minip12.c (p12_build): Change arg CERT to const void ptr. diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index ba6cf6fba..6d0236c72 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -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; } diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 819e28436..bbce179b7 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -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); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index a4b5540f1..4643fd168 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -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 */ diff --git a/sm/server.c b/sm/server.c index 22ddb5f18..d05580796 100644 --- a/sm/server.c +++ b/sm/server.c @@ -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);