diff options
Diffstat (limited to 'common/asshelp.c')
-rw-r--r-- | common/asshelp.c | 331 |
1 files changed, 155 insertions, 176 deletions
diff --git a/common/asshelp.c b/common/asshelp.c index 88d18478d..83c378786 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -56,9 +56,11 @@ operation after we started them before giving up. */ #ifdef HAVE_W32CE_SYSTEM # define SECS_TO_WAIT_FOR_AGENT 30 +# define SECS_TO_WAIT_FOR_KEYBOXD 30 # define SECS_TO_WAIT_FOR_DIRMNGR 30 #else # define SECS_TO_WAIT_FOR_AGENT 5 +# define SECS_TO_WAIT_FOR_KEYBOXD 5 # define SECS_TO_WAIT_FOR_DIRMNGR 5 #endif @@ -308,17 +310,15 @@ unlock_spawning (lock_spawn_t *lock, const char *name) } -/* Helper for start_new_gpg_agent and start_new_dirmngr. - * Values for WHICH are: - * 0 - Start gpg-agent - * 1 - Start dirmngr - * SECS give the number of seconds to wait. SOCKNAME is the name of - * the socket to connect. VERBOSE is the usual verbose flag. CTX is - * the assuan context. DID_SUCCESS_MSG will be set to 1 if a success - * messages has been printed. +/* Helper to start a service. SECS gives the number of seconds to + * wait. SOCKNAME is the name of the socket to connect. VERBOSE is + * the usual verbose flag. CTX is the assuan context. CONNECT_FLAGS + * are the assuan connect flags. DID_SUCCESS_MSG will be set to 1 if + * a success messages has been printed. */ static gpg_error_t -wait_for_sock (int secs, int which, const char *sockname, +wait_for_sock (int secs, int module_name_id, const char *sockname, + unsigned int connect_flags, int verbose, assuan_context_t ctx, int *did_success_msg) { gpg_error_t err = 0; @@ -343,8 +343,10 @@ wait_for_sock (int secs, int which, const char *sockname, /* next_sleep_us); */ if (secsleft < lastalert) { - log_info (which == 1? + log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR? _("waiting for the dirmngr to come up ... (%ds)\n"): + module_name_id == GNUPG_MODULE_NAME_KEYBOXD? + _("waiting for the keyboxd to come up ... (%ds)\n"): _("waiting for the agent to come up ... (%ds)\n"), secsleft); lastalert = secsleft; @@ -352,13 +354,15 @@ wait_for_sock (int secs, int which, const char *sockname, } gnupg_usleep (next_sleep_us); elapsed_us += next_sleep_us; - err = assuan_socket_connect (ctx, sockname, 0, 0); + err = assuan_socket_connect (ctx, sockname, 0, connect_flags); if (!err) { if (verbose) { - log_info (which == 1? + log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR? _("connection to the dirmngr established\n"): + module_name_id == GNUPG_MODULE_NAME_KEYBOXD? + _("connection to the keyboxd established\n"): _("connection to the agent established\n")); *did_success_msg = 1; } @@ -372,25 +376,35 @@ wait_for_sock (int secs, int which, const char *sockname, } -/* Try to connect to the agent via socket or start it if it is not - running and AUTOSTART is set. 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 *agent_program, - const char *opt_lc_ctype, - const char *opt_lc_messages, - session_env_t session_env, - int autostart, int verbose, int debug, - gpg_error_t (*status_cb)(ctrl_t, int, ...), - ctrl_t status_cb_arg) +/* Try to connect to a new service via socket or start it if it is not + * running and AUTOSTART is set. Handle the server's initial + * greeting. Returns a new assuan context at R_CTX or an error code. + * MODULE_NAME_ID is one of: + * GNUPG_MODULE_NAME_AGENT + * GNUPG_MODULE_NAME_DIRMNGR + */ +static gpg_error_t +start_new_service (assuan_context_t *r_ctx, + int module_name_id, + gpg_err_source_t errsource, + const char *program_name, + const char *opt_lc_ctype, + const char *opt_lc_messages, + session_env_t session_env, + int autostart, 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; int did_success_msg = 0; char *sockname; + const char *printed_name; + const char *lock_name; + const char *status_start_line; + int no_service_err; + int seconds_to_wait; + unsigned int connect_flags = 0; const char *argv[6]; *r_ctx = NULL; @@ -402,15 +416,40 @@ start_new_gpg_agent (assuan_context_t *r_ctx, return err; } - sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL); - if (!sockname) + switch (module_name_id) { - err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); + case GNUPG_MODULE_NAME_AGENT: + sockname = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL); + lock_name = "agent"; + printed_name = "gpg-agent"; + status_start_line = "starting_agent ? 0 0"; + no_service_err = GPG_ERR_NO_AGENT; + seconds_to_wait = SECS_TO_WAIT_FOR_AGENT; + break; + case GNUPG_MODULE_NAME_DIRMNGR: + sockname = make_filename (gnupg_socketdir (), DIRMNGR_SOCK_NAME, NULL); + lock_name = "dirmngr"; + printed_name = "dirmngr"; + status_start_line = "starting_dirmngr ? 0 0"; + no_service_err = GPG_ERR_NO_DIRMNGR; + seconds_to_wait = SECS_TO_WAIT_FOR_DIRMNGR; + break; + case GNUPG_MODULE_NAME_KEYBOXD: + sockname = make_filename (gnupg_socketdir (), KEYBOXD_SOCK_NAME, NULL); + lock_name = "keyboxd"; + printed_name = "keyboxd"; + status_start_line = "starting_keyboxd ? 0 0"; + no_service_err = GPG_ERR_NO_KEYBOXD; + seconds_to_wait = SECS_TO_WAIT_FOR_KEYBOXD; + connect_flags |= ASSUAN_SOCKET_CONNECT_FDPASSING; + break; + default: + err = gpg_error (GPG_ERR_INV_ARG); assuan_release (ctx); return err; } - err = assuan_socket_connect (ctx, sockname, 0, 0); + err = assuan_socket_connect (ctx, sockname, 0, connect_flags); if (err && autostart) { char *abs_homedir; @@ -422,12 +461,12 @@ start_new_gpg_agent (assuan_context_t *r_ctx, int i; /* With no success start a new server. */ - if (!agent_program || !*agent_program) - agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT); - else if ((s=strchr (agent_program, '|')) && s[1] == '-' && s[2]=='-') + if (!program_name || !*program_name) + program_name = gnupg_module_name (module_name_id); + else if ((s=strchr (program_name, '|')) && s[1] == '-' && s[2]=='-') { /* Hack to insert an additional option on the command line. */ - program = xtrystrdup (agent_program); + program = xtrystrdup (program_name); if (!program) { gpg_error_t tmperr = gpg_err_make (errsource, @@ -442,22 +481,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx, } if (verbose) - log_info (_("no running gpg-agent - starting '%s'\n"), - agent_program); + log_info (_("no running %s - starting '%s'\n"), + printed_name, program_name); if (status_cb) - status_cb (status_cb_arg, STATUS_PROGRESS, - "starting_agent ? 0 0", NULL); + status_cb (status_cb_arg, STATUS_PROGRESS, status_start_line, NULL); - /* We better pass an absolute home directory to the agent just - in case gpg-agent does not convert the passed name to an - absolute one (which it should do). */ + /* We better pass an absolute home directory to the service just + * in case the service does not convert the passed name to an + * absolute one (which it should do). */ abs_homedir = make_absfilename_try (gnupg_homedir (), NULL); if (!abs_homedir) { gpg_error_t tmperr = gpg_err_make (errsource, gpg_err_code_from_syserror ()); - log_error ("error building filename: %s\n",gpg_strerror (tmperr)); + log_error ("error building filename: %s\n", gpg_strerror (tmperr)); xfree (sockname); assuan_release (ctx); xfree (program); @@ -468,8 +506,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx, { gpg_error_t tmperr = gpg_err_make (errsource, gpg_err_code_from_syserror ()); - log_error ("error flushing pending output: %s\n", - strerror (errno)); + log_error ("error flushing pending output: %s\n", strerror (errno)); xfree (sockname); assuan_release (ctx); xfree (abs_homedir); @@ -477,42 +514,42 @@ start_new_gpg_agent (assuan_context_t *r_ctx, return tmperr; } - /* If the agent has been configured for use with a standard - socket, an environment variable is not required and thus - we can safely start the agent here. */ i = 0; argv[i++] = "--homedir"; argv[i++] = abs_homedir; - argv[i++] = "--use-standard-socket"; + if (module_name_id == GNUPG_MODULE_NAME_AGENT) + argv[i++] = "--use-standard-socket"; if (program_arg) argv[i++] = program_arg; argv[i++] = "--daemon"; argv[i++] = NULL; - if (!(err = lock_spawning (&lock, gnupg_homedir (), "agent", verbose)) - && assuan_socket_connect (ctx, sockname, 0, 0)) + if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose)) + && assuan_socket_connect (ctx, sockname, 0, connect_flags)) { #ifdef HAVE_W32_SYSTEM - err = gnupg_spawn_process_detached (program? program : agent_program, + err = gnupg_spawn_process_detached (program? program : program_name, argv, NULL); -#else +#else /*!W32*/ pid_t pid; - err = gnupg_spawn_process_fd (program? program : agent_program, + err = gnupg_spawn_process_fd (program? program : program_name, argv, -1, -1, -1, &pid); if (!err) - err = gnupg_wait_process (program? program : agent_program, + err = gnupg_wait_process (program? program : program_name, pid, 1, NULL); -#endif +#endif /*!W32*/ if (err) - log_error ("failed to start agent '%s': %s\n", - agent_program, gpg_strerror (err)); + log_error ("failed to start %s '%s': %s\n", + printed_name, program? program : program_name, + gpg_strerror (err)); else - err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, 0, - sockname, verbose, ctx, &did_success_msg); + err = wait_for_sock (seconds_to_wait, module_name_id, + sockname, connect_flags, + verbose, ctx, &did_success_msg); } - unlock_spawning (&lock, "agent"); + unlock_spawning (&lock, lock_name); xfree (abs_homedir); xfree (program); } @@ -520,17 +557,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx, if (err) { if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED) - log_error ("can't connect to the agent: %s\n", gpg_strerror (err)); + log_error ("can't connect to the %s: %s\n", + printed_name, gpg_strerror (err)); assuan_release (ctx); - return gpg_err_make (errsource, GPG_ERR_NO_AGENT); + return gpg_err_make (errsource, no_service_err); } if (debug && !did_success_msg) - log_debug ("connection to the agent established\n"); + log_debug ("connection to the %s established\n", printed_name); + + if (module_name_id == GNUPG_MODULE_NAME_AGENT) + err = assuan_transact (ctx, "RESET", + NULL, NULL, NULL, NULL, NULL, NULL); - err = assuan_transact (ctx, "RESET", - NULL, NULL, NULL, NULL, NULL, NULL); - if (!err) + if (!err + && module_name_id == GNUPG_MODULE_NAME_AGENT) { err = send_pinentry_environment (ctx, errsource, opt_lc_ctype, opt_lc_messages, @@ -538,7 +579,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx, if (gpg_err_code (err) == GPG_ERR_FORBIDDEN && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT) { - /* Check whether we are in restricted mode. */ + /* Check whether the agent is in restricted mode. */ if (!assuan_transact (ctx, "GETINFO restricted", NULL, NULL, NULL, NULL, NULL, NULL)) { @@ -559,126 +600,64 @@ start_new_gpg_agent (assuan_context_t *r_ctx, } +/* Try to connect tothe agent or start a new one. */ +gpg_error_t +start_new_gpg_agent (assuan_context_t *r_ctx, + gpg_err_source_t errsource, + const char *agent_program, + const char *opt_lc_ctype, + const char *opt_lc_messages, + session_env_t session_env, + int autostart, int verbose, int debug, + gpg_error_t (*status_cb)(ctrl_t, int, ...), + ctrl_t status_cb_arg) +{ + return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT, + errsource, agent_program, + opt_lc_ctype, opt_lc_messages, session_env, + autostart, verbose, debug, + status_cb, status_cb_arg); +} + + /* Try to connect to the dirmngr via a socket. On platforms supporting it, start it up if needed and if AUTOSTART is true. Returns a new assuan context at R_CTX or an error code. */ gpg_error_t -start_new_dirmngr (assuan_context_t *r_ctx, +start_new_keyboxd (assuan_context_t *r_ctx, gpg_err_source_t errsource, - const char *dirmngr_program, - int autostart, - int verbose, int debug, + const char *keyboxd_program, + int autostart, 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; - int did_success_msg = 0; - - *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); - -#ifdef USE_DIRMNGR_AUTO_START - if (err && autostart) - { - lock_spawn_t lock; - const char *argv[4]; - char *abs_homedir; - - /* No connection: Try start a new Dirmngr. */ - if (!dirmngr_program || !*dirmngr_program) - dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR); - - if (verbose) - log_info (_("no running dirmngr - starting '%s'\n"), - dirmngr_program); - - if (status_cb) - status_cb (status_cb_arg, STATUS_PROGRESS, - "starting_dirmngr ? 0 0", NULL); - - abs_homedir = make_absfilename (gnupg_homedir (), NULL); - if (!abs_homedir) - { - gpg_error_t tmperr = gpg_err_make (errsource, - gpg_err_code_from_syserror ()); - log_error ("error building filename: %s\n",gpg_strerror (tmperr)); - assuan_release (ctx); - return tmperr; - } - - 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; - } + return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD, + errsource, keyboxd_program, + NULL, NULL, NULL, + autostart, verbose, debug, + status_cb, status_cb_arg); +} - argv[0] = "--daemon"; - /* Try starting the daemon. Versions of dirmngr < 2.1.15 do - * this only if the home directory is given on the command line. */ - argv[1] = "--homedir"; - argv[2] = abs_homedir; - argv[3] = NULL; - if (!(err = lock_spawning (&lock, gnupg_homedir (), "dirmngr", verbose)) - && assuan_socket_connect (ctx, sockname, 0, 0)) - { -#ifdef HAVE_W32_SYSTEM - err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL); -#else - pid_t pid; - - err = gnupg_spawn_process_fd (dirmngr_program, argv, - -1, -1, -1, &pid); - if (!err) - err = gnupg_wait_process (dirmngr_program, pid, 1, NULL); +/* Try to connect to the dirmngr via a socket. On platforms + supporting it, start it up if needed and if AUTOSTART is true. + 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 *dirmngr_program, + int autostart, int verbose, int debug, + gpg_error_t (*status_cb)(ctrl_t, int, ...), + ctrl_t status_cb_arg) +{ +#ifndef USE_DIRMNGR_AUTO_START + autostart = 0; #endif - if (err) - log_error ("failed to start the dirmngr '%s': %s\n", - dirmngr_program, gpg_strerror (err)); - else - err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, 1, - sockname, verbose, ctx, &did_success_msg); - } - - unlock_spawning (&lock, "dirmngr"); - xfree (abs_homedir); - } -#else - (void)dirmngr_program; - (void)verbose; - (void)status_cb; - (void)status_cb_arg; -#endif /*USE_DIRMNGR_AUTO_START*/ - - if (err) - { - if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED) - 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 && !did_success_msg) - log_debug ("connection to the dirmngr established\n"); - - *r_ctx = ctx; - return 0; + return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR, + errsource, dirmngr_program, + NULL, NULL, NULL, + autostart, verbose, debug, + status_cb, status_cb_arg); } |