LCOV - code coverage report
Current view: top level - common - asshelp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 130 257 50.6 %
Date: 2015-11-05 17:10:59 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /* asshelp.c - Helper functions for Assuan
       2             :  * Copyright (C) 2002, 2004, 2007, 2009, 2010 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * This file is free software; you can redistribute it and/or modify
       7             :  * it under the terms of either
       8             :  *
       9             :  *   - the GNU Lesser General Public License as published by the Free
      10             :  *     Software Foundation; either version 3 of the License, or (at
      11             :  *     your option) any later version.
      12             :  *
      13             :  * or
      14             :  *
      15             :  *   - the GNU General Public License as published by the Free
      16             :  *     Software Foundation; either version 2 of the License, or (at
      17             :  *     your option) any later version.
      18             :  *
      19             :  * or both in parallel, as here.
      20             :  *
      21             :  * This file is distributed in the hope that it will be useful,
      22             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24             :  * GNU General Public License for more details.
      25             :  *
      26             :  * You should have received a copy of the GNU General Public License
      27             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      28             :  */
      29             : 
      30             : #include <config.h>
      31             : #include <stdio.h>
      32             : #include <stdlib.h>
      33             : #include <string.h>
      34             : #include <unistd.h>
      35             : #include <errno.h>
      36             : #ifdef HAVE_LOCALE_H
      37             : #include <locale.h>
      38             : #endif
      39             : 
      40             : #include "i18n.h"
      41             : #include "util.h"
      42             : #include "exechelp.h"
      43             : #include "sysutils.h"
      44             : #include "status.h"
      45             : #include "asshelp.h"
      46             : 
      47             : /* The type we use for lock_agent_spawning.  */
      48             : #ifdef HAVE_W32_SYSTEM
      49             : # define lock_spawn_t HANDLE
      50             : #else
      51             : # define lock_spawn_t dotlock_t
      52             : #endif
      53             : 
      54             : /* The time we wait until the agent or the dirmngr are ready for
      55             :    operation after we started them before giving up.  */
      56             : #ifdef HAVE_W32CE_SYSTEM
      57             : # define SECS_TO_WAIT_FOR_AGENT 30
      58             : # define SECS_TO_WAIT_FOR_DIRMNGR 30
      59             : #else
      60             : # define SECS_TO_WAIT_FOR_AGENT 5
      61             : # define SECS_TO_WAIT_FOR_DIRMNGR 5
      62             : #endif
      63             : 
      64             : /* A bitfield that specifies the assuan categories to log.  This is
      65             :    identical to the default log handler of libassuan.  We need to do
      66             :    it ourselves because we use a custom log handler and want to use
      67             :    the same assuan variables to select the categories to log. */
      68             : static int log_cats;
      69             : #define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1))))
      70             : 
      71             : 
      72             : static int
      73       37077 : my_libassuan_log_handler (assuan_context_t ctx, void *hook,
      74             :                           unsigned int cat, const char *msg)
      75             : {
      76             :   unsigned int dbgval;
      77             : 
      78             :   (void)ctx;
      79             : 
      80       37077 :   if (! TEST_LOG_CAT (cat))
      81        7734 :     return 0;
      82             : 
      83       29343 :   dbgval = hook? *(unsigned int*)hook : 0;
      84       29343 :   if (!(dbgval & 1024))
      85       29343 :     return 0; /* Assuan debugging is not enabled.  */
      86             : 
      87           0 :   if (msg)
      88           0 :     log_string (GPGRT_LOG_DEBUG, msg);
      89             : 
      90           0 :   return 1;
      91             : }
      92             : 
      93             : 
      94             : /* Setup libassuan to use our own logging functions.  Should be used
      95             :    early at startup.  */
      96             : void
      97        1305 : setup_libassuan_logging (unsigned int *debug_var_address)
      98             : {
      99             :   char *flagstr;
     100             : 
     101        1305 :   flagstr = getenv ("ASSUAN_DEBUG");
     102        1305 :   if (flagstr)
     103           0 :     log_cats = atoi (flagstr);
     104             :   else /* Default to log the control channel.  */
     105        1305 :     log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
     106        1305 :   assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
     107        1305 : }
     108             : 
     109             : /* Change the Libassuan log categories to those given by NEWCATS.
     110             :    NEWCATS is 0 the default category of ASSUAN_LOG_CONTROL is
     111             :    selected.  Note, that setup_libassuan_logging overrides the values
     112             :    given here.  */
     113             : void
     114           0 : set_libassuan_log_cats (unsigned int newcats)
     115             : {
     116           0 :   if (newcats)
     117           0 :     log_cats = newcats;
     118             :   else /* Default to log the control channel.  */
     119           0 :     log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
     120           0 : }
     121             : 
     122             : 
     123             : 
     124             : static gpg_error_t
     125        2145 : send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
     126             :                  const char *name, const char *value, int use_putenv)
     127             : {
     128             :   gpg_error_t err;
     129             :   char *optstr;
     130             : 
     131             :   (void)errsource;
     132             : 
     133        2145 :   if (!value || !*value)
     134           0 :     err = 0;  /* Avoid sending empty strings.  */
     135        2145 :   else if (asprintf (&optstr, "OPTION %s%s=%s",
     136             :                      use_putenv? "putenv=":"", name, value) < 0)
     137           0 :     err = gpg_error_from_syserror ();
     138             :   else
     139             :     {
     140        2145 :       err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
     141        2145 :       xfree (optstr);
     142             :     }
     143             : 
     144        2145 :   return err;
     145             : }
     146             : 
     147             : 
     148             : /* Send the assuan commands pertaining to the pinentry environment.  The
     149             :    OPT_* arguments are optional and may be used to override the
     150             :    defaults taken from the current locale. */
     151             : gpg_error_t
     152         393 : send_pinentry_environment (assuan_context_t ctx,
     153             :                            gpg_err_source_t errsource,
     154             :                            const char *opt_lc_ctype,
     155             :                            const char *opt_lc_messages,
     156             :                            session_env_t session_env)
     157             : 
     158             : {
     159         393 :   gpg_error_t err = 0;
     160             : #if defined(HAVE_SETLOCALE)
     161         393 :   char *old_lc = NULL;
     162             : #endif
     163         393 :   char *dft_lc = NULL;
     164             :   const char *dft_ttyname;
     165             :   int iterator;
     166             :   const char *name, *assname, *value;
     167             :   int is_default;
     168             : 
     169         393 :   iterator = 0;
     170        4716 :   while ((name = session_env_list_stdenvnames (&iterator, &assname)))
     171             :     {
     172        3930 :       value = session_env_getenv_or_default (session_env, name, NULL);
     173        3930 :       if (!value)
     174        2395 :         continue;
     175             : 
     176        1535 :       if (assname)
     177        1142 :         err = send_one_option (ctx, errsource, assname, value, 0);
     178             :       else
     179             :         {
     180         393 :           err = send_one_option (ctx, errsource, name, value, 1);
     181         393 :           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
     182           0 :             err = 0;  /* Server too old; can't pass the new envvars.  */
     183             :         }
     184        1535 :       if (err)
     185           0 :         return err;
     186             :     }
     187             : 
     188             : 
     189         393 :   dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY",
     190             :                                                &is_default);
     191         393 :   if (dft_ttyname && !is_default)
     192           0 :     dft_ttyname = NULL;  /* We need the default value.  */
     193             : 
     194             :   /* Send the value for LC_CTYPE.  */
     195             : #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
     196         393 :   old_lc = setlocale (LC_CTYPE, NULL);
     197         393 :   if (old_lc)
     198             :     {
     199         393 :       old_lc = xtrystrdup (old_lc);
     200         393 :       if (!old_lc)
     201           0 :         return gpg_error_from_syserror ();
     202             :     }
     203         393 :   dft_lc = setlocale (LC_CTYPE, "");
     204             : #endif
     205         393 :   if (opt_lc_ctype || (dft_ttyname && dft_lc))
     206             :     {
     207         305 :       err = send_one_option (ctx, errsource, "lc-ctype",
     208             :                              opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
     209             :     }
     210             : #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
     211         393 :   if (old_lc)
     212             :     {
     213         393 :       setlocale (LC_CTYPE, old_lc);
     214         393 :       xfree (old_lc);
     215             :     }
     216             : #endif
     217         393 :   if (err)
     218           0 :     return err;
     219             : 
     220             :   /* Send the value for LC_MESSAGES.  */
     221             : #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
     222         393 :   old_lc = setlocale (LC_MESSAGES, NULL);
     223         393 :   if (old_lc)
     224             :     {
     225         393 :       old_lc = xtrystrdup (old_lc);
     226         393 :       if (!old_lc)
     227           0 :         return gpg_error_from_syserror ();
     228             :     }
     229         393 :   dft_lc = setlocale (LC_MESSAGES, "");
     230             : #endif
     231         393 :   if (opt_lc_messages || (dft_ttyname && dft_lc))
     232             :     {
     233         305 :       err = send_one_option (ctx, errsource, "lc-messages",
     234             :                              opt_lc_messages ? opt_lc_messages : dft_lc, 0);
     235             :     }
     236             : #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
     237         393 :   if (old_lc)
     238             :     {
     239         393 :       setlocale (LC_MESSAGES, old_lc);
     240         393 :       xfree (old_lc);
     241             :     }
     242             : #endif
     243         393 :   if (err)
     244           0 :     return err;
     245             : 
     246         393 :   return 0;
     247             : }
     248             : 
     249             : 
     250             : /* Lock a spawning process.  The caller needs to provide the address
     251             :    of a variable to store the lock information and the name or the
     252             :    process.  */
     253             : static gpg_error_t
     254           1 : lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name,
     255             :                int verbose)
     256             : {
     257             : #ifdef HAVE_W32_SYSTEM
     258             :   int waitrc;
     259             :   int timeout = (!strcmp (name, "agent")
     260             :                  ? SECS_TO_WAIT_FOR_AGENT
     261             :                  : SECS_TO_WAIT_FOR_DIRMNGR);
     262             : 
     263             :   (void)homedir; /* Not required. */
     264             : 
     265             :   *lock = CreateMutexW
     266             :     (NULL, FALSE,
     267             :      !strcmp (name, "agent")?   L"spawn_"GNUPG_NAME"_agent_sentinel":
     268             :      !strcmp (name, "dirmngr")? L"spawn_"GNUPG_NAME"_dirmngr_sentinel":
     269             :      /*                    */   L"spawn_"GNUPG_NAME"_unknown_sentinel");
     270             :   if (!*lock)
     271             :     {
     272             :       log_error ("failed to create the spawn_%s mutex: %s\n",
     273             :                  name, w32_strerror (-1));
     274             :       return gpg_error (GPG_ERR_GENERAL);
     275             :     }
     276             : 
     277             :  retry:
     278             :   waitrc = WaitForSingleObject (*lock, 1000);
     279             :   if (waitrc == WAIT_OBJECT_0)
     280             :     return 0;
     281             : 
     282             :   if (waitrc == WAIT_TIMEOUT && timeout)
     283             :     {
     284             :       timeout--;
     285             :       if (verbose)
     286             :         log_info ("another process is trying to start the %s ... (%ds)\n",
     287             :                   name, timeout);
     288             :       goto retry;
     289             :     }
     290             :   if (waitrc == WAIT_TIMEOUT)
     291             :     log_info ("error waiting for the spawn_%s mutex: timeout\n", name);
     292             :   else
     293             :     log_info ("error waiting for the spawn_%s mutex: (code=%d) %s\n",
     294             :               name, waitrc, w32_strerror (-1));
     295             :   return gpg_error (GPG_ERR_GENERAL);
     296             : #else /*!HAVE_W32_SYSTEM*/
     297             :   char *fname;
     298             : 
     299             :   (void)verbose;
     300             : 
     301           1 :   *lock = NULL;
     302             : 
     303           1 :   fname = make_absfilename_try
     304             :     (homedir,
     305           1 :      !strcmp (name, "agent")?   "gnupg_spawn_agent_sentinel":
     306           0 :      !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
     307             :      /*                    */   "gnupg_spawn_unknown_sentinel",
     308             :      NULL);
     309           1 :   if (!fname)
     310           0 :     return gpg_error_from_syserror ();
     311             : 
     312           1 :   *lock = dotlock_create (fname, 0);
     313           1 :   xfree (fname);
     314           1 :   if (!*lock)
     315           0 :     return gpg_error_from_syserror ();
     316             : 
     317             :   /* FIXME: We should use a timeout of 5000 here - however
     318             :      make_dotlock does not yet support values other than -1 and 0.  */
     319           1 :   if (dotlock_take (*lock, -1))
     320           0 :     return gpg_error_from_syserror ();
     321             : 
     322           1 :   return 0;
     323             : #endif /*!HAVE_W32_SYSTEM*/
     324             : }
     325             : 
     326             : 
     327             : /* Unlock the spawning process.  */
     328             : static void
     329           1 : unlock_spawning (lock_spawn_t *lock, const char *name)
     330             : {
     331           1 :   if (*lock)
     332             :     {
     333             : #ifdef HAVE_W32_SYSTEM
     334             :       if (!ReleaseMutex (*lock))
     335             :         log_error ("failed to release the spawn_%s mutex: %s\n",
     336             :                    name, w32_strerror (-1));
     337             :       CloseHandle (*lock);
     338             : #else /*!HAVE_W32_SYSTEM*/
     339             :       (void)name;
     340           1 :       dotlock_destroy (*lock);
     341             : #endif /*!HAVE_W32_SYSTEM*/
     342           1 :       *lock = NULL;
     343             :     }
     344           1 : }
     345             : 
     346             : /* Try to connect to the agent via socket or start it if it is not
     347             :    running and AUTOSTART is set.  Handle the server's initial
     348             :    greeting.  Returns a new assuan context at R_CTX or an error
     349             :    code. */
     350             : gpg_error_t
     351         393 : start_new_gpg_agent (assuan_context_t *r_ctx,
     352             :                      gpg_err_source_t errsource,
     353             :                      const char *homedir,
     354             :                      const char *agent_program,
     355             :                      const char *opt_lc_ctype,
     356             :                      const char *opt_lc_messages,
     357             :                      session_env_t session_env,
     358             :                      int autostart, int verbose, int debug,
     359             :                      gpg_error_t (*status_cb)(ctrl_t, int, ...),
     360             :                      ctrl_t status_cb_arg)
     361             : {
     362             :   gpg_error_t err;
     363             :   assuan_context_t ctx;
     364         393 :   int did_success_msg = 0;
     365             :   char *sockname;
     366             :   const char *argv[6];
     367             : 
     368         393 :   *r_ctx = NULL;
     369             : 
     370         393 :   err = assuan_new (&ctx);
     371         393 :   if (err)
     372             :     {
     373           0 :       log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
     374           0 :       return err;
     375             :     }
     376             : 
     377         393 :   sockname = make_absfilename (homedir, GPG_AGENT_SOCK_NAME, NULL);
     378         393 :   err = assuan_socket_connect (ctx, sockname, 0, 0);
     379         393 :   if (err && autostart)
     380             :     {
     381             :       char *abs_homedir;
     382             :       lock_spawn_t lock;
     383           1 :       char *program = NULL;
     384           1 :       const char *program_arg = NULL;
     385             :       char *p;
     386             :       const char *s;
     387             :       int i;
     388             : 
     389             :       /* With no success start a new server.  */
     390           1 :       if (!agent_program || !*agent_program)
     391           0 :         agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
     392           1 :       else if ((s=strchr (agent_program, '|')) && s[1] == '-' && s[2]=='-')
     393             :         {
     394             :           /* Hack to insert an additional option on the command line.  */
     395           1 :           program = xtrystrdup (agent_program);
     396           1 :           if (!program)
     397             :             {
     398           0 :               gpg_error_t tmperr = gpg_err_make (errsource,
     399             :                                                  gpg_err_code_from_syserror ());
     400           0 :               xfree (sockname);
     401           0 :               assuan_release (ctx);
     402           0 :               return tmperr;
     403             :             }
     404           1 :           p = strchr (program, '|');
     405           1 :           *p++ = 0;
     406           1 :           program_arg = p;
     407             :         }
     408             : 
     409           1 :       if (verbose)
     410           1 :         log_info (_("no running gpg-agent - starting '%s'\n"),
     411             :                   agent_program);
     412             : 
     413           1 :       if (status_cb)
     414           0 :         status_cb (status_cb_arg, STATUS_PROGRESS,
     415             :                    "starting_agent ? 0 0", NULL);
     416             : 
     417             :       /* We better pass an absolute home directory to the agent just
     418             :          in case gpg-agent does not convert the passed name to an
     419             :          absolute one (which it should do).  */
     420           1 :       abs_homedir = make_absfilename_try (homedir, NULL);
     421           1 :       if (!abs_homedir)
     422             :         {
     423           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     424             :                                              gpg_err_code_from_syserror ());
     425           0 :           log_error ("error building filename: %s\n",gpg_strerror (tmperr));
     426           0 :           xfree (sockname);
     427           0 :           assuan_release (ctx);
     428           0 :           xfree (program);
     429           0 :           return tmperr;
     430             :         }
     431             : 
     432           1 :       if (fflush (NULL))
     433             :         {
     434           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     435             :                                              gpg_err_code_from_syserror ());
     436           0 :           log_error ("error flushing pending output: %s\n",
     437           0 :                      strerror (errno));
     438           0 :           xfree (sockname);
     439           0 :           assuan_release (ctx);
     440           0 :           xfree (abs_homedir);
     441           0 :           xfree (program);
     442           0 :           return tmperr;
     443             :         }
     444             : 
     445             :       /* If the agent has been configured for use with a standard
     446             :          socket, an environment variable is not required and thus
     447             :          we we can savely start the agent here.  */
     448           1 :       i = 0;
     449           1 :       argv[i++] = "--homedir";
     450           1 :       argv[i++] = abs_homedir;
     451           1 :       argv[i++] = "--use-standard-socket";
     452           1 :       if (program_arg)
     453           1 :         argv[i++] = program_arg;
     454           1 :       argv[i++] = "--daemon";
     455           1 :       argv[i++] = NULL;
     456             : 
     457           1 :       if (!(err = lock_spawning (&lock, homedir, "agent", verbose))
     458           1 :           && assuan_socket_connect (ctx, sockname, 0, 0))
     459             :         {
     460           1 :           err = gnupg_spawn_process_detached (program? program : agent_program,
     461             :                                               argv, NULL);
     462           1 :           if (err)
     463           0 :             log_error ("failed to start agent '%s': %s\n",
     464             :                        agent_program, gpg_strerror (err));
     465             :           else
     466             :             {
     467           1 :               for (i=0; i < SECS_TO_WAIT_FOR_AGENT; i++)
     468             :                 {
     469           1 :                   if (verbose)
     470           1 :                     log_info (_("waiting for the agent to come up ... (%ds)\n"),
     471             :                               SECS_TO_WAIT_FOR_AGENT - i);
     472           1 :                   gnupg_sleep (1);
     473           1 :                   err = assuan_socket_connect (ctx, sockname, 0, 0);
     474           1 :                   if (!err)
     475             :                     {
     476           1 :                       if (verbose)
     477             :                         {
     478           1 :                           log_info (_("connection to agent established\n"));
     479           1 :                           did_success_msg = 1;
     480             :                         }
     481           1 :                       break;
     482             :                     }
     483             :                 }
     484             :             }
     485             :         }
     486             : 
     487           1 :       unlock_spawning (&lock, "agent");
     488           1 :       xfree (abs_homedir);
     489           1 :       xfree (program);
     490             :     }
     491         393 :   xfree (sockname);
     492         393 :   if (err)
     493             :     {
     494           0 :       if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
     495           0 :         log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
     496           0 :       assuan_release (ctx);
     497           0 :       return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
     498             :     }
     499             : 
     500         393 :   if (debug && !did_success_msg)
     501           0 :     log_debug (_("connection to agent established\n"));
     502             : 
     503         393 :   err = assuan_transact (ctx, "RESET",
     504             :                          NULL, NULL, NULL, NULL, NULL, NULL);
     505         393 :   if (!err)
     506             :     {
     507         393 :       err = send_pinentry_environment (ctx, errsource,
     508             :                                        opt_lc_ctype, opt_lc_messages,
     509             :                                        session_env);
     510         393 :       if (gpg_err_code (err) == GPG_ERR_FORBIDDEN
     511           0 :           && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT)
     512             :         {
     513             :           /* Check whether we are in restricted mode.  */
     514           0 :           if (!assuan_transact (ctx, "GETINFO restricted",
     515             :                                 NULL, NULL, NULL, NULL, NULL, NULL))
     516             :             {
     517           0 :               if (verbose)
     518           0 :                 log_info (_("connection to agent is in restricted mode\n"));
     519           0 :               err = 0;
     520             :             }
     521             :         }
     522             :     }
     523         393 :   if (err)
     524             :     {
     525           0 :       assuan_release (ctx);
     526           0 :       return err;
     527             :     }
     528             : 
     529         393 :   *r_ctx = ctx;
     530         393 :   return 0;
     531             : }
     532             : 
     533             : 
     534             : /* Try to connect to the dirmngr via a socket.  On platforms
     535             :    supporting it, start it up if needed and if AUTOSTART is true.
     536             :    Returns a new assuan context at R_CTX or an error code. */
     537             : gpg_error_t
     538           0 : start_new_dirmngr (assuan_context_t *r_ctx,
     539             :                    gpg_err_source_t errsource,
     540             :                    const char *homedir,
     541             :                    const char *dirmngr_program,
     542             :                    int autostart,
     543             :                    int verbose, int debug,
     544             :                    gpg_error_t (*status_cb)(ctrl_t, int, ...),
     545             :                    ctrl_t status_cb_arg)
     546             : {
     547             :   gpg_error_t err;
     548             :   assuan_context_t ctx;
     549             :   const char *sockname;
     550           0 :   int did_success_msg = 0;
     551             : 
     552           0 :   *r_ctx = NULL;
     553             : 
     554           0 :   err = assuan_new (&ctx);
     555           0 :   if (err)
     556             :     {
     557           0 :       log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
     558           0 :       return err;
     559             :     }
     560             : 
     561           0 :   sockname = dirmngr_user_socket_name ();
     562           0 :   if (sockname)
     563             :     {
     564             :       /* First try the local socket name and only if that fails try
     565             :          the system socket.  */
     566           0 :       err = assuan_socket_connect (ctx, sockname, 0, 0);
     567           0 :       if (err)
     568           0 :         sockname = dirmngr_sys_socket_name ();
     569             :     }
     570             :   else
     571           0 :     sockname = dirmngr_sys_socket_name ();
     572             : 
     573           0 :   err = assuan_socket_connect (ctx, sockname, 0, 0);
     574             : 
     575             : #ifdef USE_DIRMNGR_AUTO_START
     576           0 :   if (err && autostart)
     577             :     {
     578             :       lock_spawn_t lock;
     579             :       const char *argv[4];
     580           0 :       int try_system_daemon = 0;
     581             :       char *abs_homedir;
     582             : 
     583             :       /* No connection: Try start a new Dirmngr.  On Windows this will
     584             :          fail because the Dirmngr is expected to be a system service.
     585             :          However on WinCE we don't distinguish users and thus we can
     586             :          start it.  */
     587             : 
     588             :       /* We prefer to start it as a user daemon.  */
     589           0 :       sockname = dirmngr_user_socket_name ();
     590           0 :       if (!sockname)
     591             :         {
     592           0 :           sockname = dirmngr_sys_socket_name ();
     593           0 :           try_system_daemon = 1;
     594             :         }
     595             : 
     596           0 :       if (!dirmngr_program || !*dirmngr_program)
     597           0 :         dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
     598             : 
     599           0 :       if (verbose)
     600           0 :         log_info (_("no running Dirmngr - starting '%s'\n"),
     601             :                   dirmngr_program);
     602             : 
     603           0 :       if (status_cb)
     604           0 :         status_cb (status_cb_arg, STATUS_PROGRESS,
     605             :                    "starting_dirmngr ? 0 0", NULL);
     606             : 
     607           0 :       abs_homedir = make_absfilename (homedir, NULL);
     608           0 :       if (!abs_homedir)
     609             :         {
     610           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     611             :                                              gpg_err_code_from_syserror ());
     612           0 :           log_error ("error building filename: %s\n",gpg_strerror (tmperr));
     613           0 :           assuan_release (ctx);
     614           0 :           return tmperr;
     615             :         }
     616             : 
     617           0 :       if (fflush (NULL))
     618             :         {
     619           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     620             :                                              gpg_err_code_from_syserror ());
     621           0 :           log_error ("error flushing pending output: %s\n",
     622           0 :                      strerror (errno));
     623           0 :           assuan_release (ctx);
     624           0 :           return tmperr;
     625             :         }
     626             : 
     627           0 :       argv[0] = "--daemon";
     628           0 :       if (try_system_daemon)
     629           0 :         argv[1] = NULL;
     630             :       else
     631             :         { /* Try starting as user daemon - dirmngr does this if the
     632             :              home directory is given on the command line.  */
     633           0 :           argv[1] = "--homedir";
     634           0 :           argv[2] = abs_homedir;
     635           0 :           argv[3] = NULL;
     636             :         }
     637             : 
     638             :       /* On the use of HOMEDIR for locking: Under Windows HOMEDIR is
     639             :          not used thus it does not matter.  Under Unix we should
     640             :          TRY_SYSTEM_DAEMON should never be true because
     641             :          dirmngr_user_socket_name() won't return NULL.  */
     642             : 
     643           0 :       if (!(err = lock_spawning (&lock, homedir, "dirmngr", verbose))
     644           0 :           && assuan_socket_connect (ctx, sockname, 0, 0))
     645             :         {
     646           0 :           err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL);
     647           0 :           if (err)
     648           0 :             log_error ("failed to start the dirmngr '%s': %s\n",
     649             :                        dirmngr_program, gpg_strerror (err));
     650             :           else
     651             :             {
     652             :               int i;
     653             : 
     654           0 :               for (i=0; i < SECS_TO_WAIT_FOR_DIRMNGR; i++)
     655             :                 {
     656           0 :                   if (verbose)
     657           0 :                     log_info (_("waiting for the dirmngr "
     658             :                                 "to come up ... (%ds)\n"),
     659             :                               SECS_TO_WAIT_FOR_DIRMNGR - i);
     660           0 :                   gnupg_sleep (1);
     661           0 :                   err = assuan_socket_connect (ctx, sockname, 0, 0);
     662           0 :                   if (!err)
     663             :                     {
     664           0 :                       if (verbose)
     665             :                         {
     666           0 :                           log_info (_("connection to the dirmngr"
     667             :                                       " established\n"));
     668           0 :                           did_success_msg = 1;
     669             :                         }
     670           0 :                       break;
     671             :                     }
     672             :                 }
     673             :             }
     674             :         }
     675             : 
     676           0 :       unlock_spawning (&lock, "dirmngr");
     677           0 :       xfree (abs_homedir);
     678             :     }
     679             : #else
     680             :   (void)homedir;
     681             :   (void)dirmngr_program;
     682             :   (void)verbose;
     683             :   (void)status_cb;
     684             :   (void)status_cb_arg;
     685             : #endif /*USE_DIRMNGR_AUTO_START*/
     686             : 
     687           0 :   if (err)
     688             :     {
     689           0 :       if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
     690           0 :         log_error ("connecting dirmngr at '%s' failed: %s\n",
     691             :                    sockname, gpg_strerror (err));
     692           0 :       assuan_release (ctx);
     693           0 :       return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
     694             :     }
     695             : 
     696           0 :   if (debug && !did_success_msg)
     697           0 :     log_debug (_("connection to the dirmngr established\n"));
     698             : 
     699           0 :   *r_ctx = ctx;
     700           0 :   return 0;
     701             : }

Generated by: LCOV version 1.11