LCOV - code coverage report
Current view: top level - common - asshelp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 138 263 52.5 %
Date: 2016-12-01 18:37:21 Functions: 8 10 80.0 %

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

Generated by: LCOV version 1.11