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-09-12 12:29:17 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 <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 "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       47066 : my_libassuan_log_handler (assuan_context_t ctx, void *hook,
      81             :                           unsigned int cat, const char *msg)
      82             : {
      83             :   unsigned int dbgval;
      84             : 
      85       47066 :   if (! TEST_LOG_CAT (cat))
      86       12799 :     return 0;
      87             : 
      88       34267 :   dbgval = hook? *(unsigned int*)hook : 0;
      89       34267 :   if (!(dbgval & 1024))
      90       34267 :     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        1754 : 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        1754 :   flagstr = getenv ("ASSUAN_DEBUG");
     113        1754 :   if (flagstr)
     114           0 :     log_cats = atoi (flagstr);
     115             :   else /* Default to log the control channel.  */
     116        1754 :     log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
     117        1754 :   my_log_monitor = log_monitor;
     118        1754 :   assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
     119        1754 : }
     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        1638 : 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        1638 :   if (!value || !*value)
     147           0 :     err = 0;  /* Avoid sending empty strings.  */
     148        1638 :   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        1638 :       err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
     154        1638 :       xfree (optstr);
     155             :     }
     156             : 
     157        1638 :   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         527 : 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         527 :   gpg_error_t err = 0;
     173             : #if defined(HAVE_SETLOCALE)
     174         527 :   char *old_lc = NULL;
     175             : #endif
     176         527 :   char *dft_lc = NULL;
     177             :   const char *dft_ttyname;
     178             :   int iterator;
     179             :   const char *name, *assname, *value;
     180             :   int is_default;
     181             : 
     182         527 :   iterator = 0;
     183        6324 :   while ((name = session_env_list_stdenvnames (&iterator, &assname)))
     184             :     {
     185        5270 :       value = session_env_getenv_or_default (session_env, name, NULL);
     186        5270 :       if (!value)
     187        3632 :         continue;
     188             : 
     189        1638 :       if (assname)
     190        1111 :         err = send_one_option (ctx, errsource, assname, value, 0);
     191             :       else
     192             :         {
     193         527 :           err = send_one_option (ctx, errsource, name, value, 1);
     194         527 :           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
     195           0 :             err = 0;  /* Server too old; can't pass the new envvars.  */
     196             :         }
     197        1638 :       if (err)
     198           0 :         return err;
     199             :     }
     200             : 
     201             : 
     202         527 :   dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY",
     203             :                                                &is_default);
     204         527 :   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         527 :   old_lc = setlocale (LC_CTYPE, NULL);
     210         527 :   if (old_lc)
     211             :     {
     212         527 :       old_lc = xtrystrdup (old_lc);
     213         527 :       if (!old_lc)
     214           0 :         return gpg_error_from_syserror ();
     215             :     }
     216         527 :   dft_lc = setlocale (LC_CTYPE, "");
     217             : #endif
     218         527 :   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         527 :   if (old_lc)
     225             :     {
     226         527 :       setlocale (LC_CTYPE, old_lc);
     227         527 :       xfree (old_lc);
     228             :     }
     229             : #endif
     230         527 :   if (err)
     231           0 :     return err;
     232             : 
     233             :   /* Send the value for LC_MESSAGES.  */
     234             : #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
     235         527 :   old_lc = setlocale (LC_MESSAGES, NULL);
     236         527 :   if (old_lc)
     237             :     {
     238         527 :       old_lc = xtrystrdup (old_lc);
     239         527 :       if (!old_lc)
     240           0 :         return gpg_error_from_syserror ();
     241             :     }
     242         527 :   dft_lc = setlocale (LC_MESSAGES, "");
     243             : #endif
     244         527 :   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         527 :   if (old_lc)
     251             :     {
     252         527 :       setlocale (LC_MESSAGES, old_lc);
     253         527 :       xfree (old_lc);
     254             :     }
     255             : #endif
     256         527 :   if (err)
     257           0 :     return err;
     258             : 
     259         527 :   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          48 : lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name,
     268             :                int verbose)
     269             : {
     270             : #ifdef HAVE_W32_SYSTEM
     271             :   int waitrc;
     272             :   int timeout = (!strcmp (name, "agent")
     273             :                  ? SECS_TO_WAIT_FOR_AGENT
     274             :                  : SECS_TO_WAIT_FOR_DIRMNGR);
     275             : 
     276             :   (void)homedir; /* Not required. */
     277             : 
     278             :   *lock = CreateMutexW
     279             :     (NULL, FALSE,
     280             :      !strcmp (name, "agent")?   L"spawn_"GNUPG_NAME"_agent_sentinel":
     281             :      !strcmp (name, "dirmngr")? L"spawn_"GNUPG_NAME"_dirmngr_sentinel":
     282             :      /*                    */   L"spawn_"GNUPG_NAME"_unknown_sentinel");
     283             :   if (!*lock)
     284             :     {
     285             :       log_error ("failed to create the spawn_%s mutex: %s\n",
     286             :                  name, w32_strerror (-1));
     287             :       return gpg_error (GPG_ERR_GENERAL);
     288             :     }
     289             : 
     290             :  retry:
     291             :   waitrc = WaitForSingleObject (*lock, 1000);
     292             :   if (waitrc == WAIT_OBJECT_0)
     293             :     return 0;
     294             : 
     295             :   if (waitrc == WAIT_TIMEOUT && timeout)
     296             :     {
     297             :       timeout--;
     298             :       if (verbose)
     299             :         log_info ("another process is trying to start the %s ... (%ds)\n",
     300             :                   name, timeout);
     301             :       goto retry;
     302             :     }
     303             :   if (waitrc == WAIT_TIMEOUT)
     304             :     log_info ("error waiting for the spawn_%s mutex: timeout\n", name);
     305             :   else
     306             :     log_info ("error waiting for the spawn_%s mutex: (code=%d) %s\n",
     307             :               name, waitrc, w32_strerror (-1));
     308             :   return gpg_error (GPG_ERR_GENERAL);
     309             : #else /*!HAVE_W32_SYSTEM*/
     310             :   char *fname;
     311             : 
     312             :   (void)verbose;
     313             : 
     314          48 :   *lock = NULL;
     315             : 
     316          48 :   fname = make_absfilename_try
     317             :     (homedir,
     318          48 :      !strcmp (name, "agent")?   "gnupg_spawn_agent_sentinel":
     319           0 :      !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
     320             :      /*                    */   "gnupg_spawn_unknown_sentinel",
     321             :      NULL);
     322          48 :   if (!fname)
     323           0 :     return gpg_error_from_syserror ();
     324             : 
     325          48 :   *lock = dotlock_create (fname, 0);
     326          48 :   xfree (fname);
     327          48 :   if (!*lock)
     328           0 :     return gpg_error_from_syserror ();
     329             : 
     330             :   /* FIXME: We should use a timeout of 5000 here - however
     331             :      make_dotlock does not yet support values other than -1 and 0.  */
     332          48 :   if (dotlock_take (*lock, -1))
     333           0 :     return gpg_error_from_syserror ();
     334             : 
     335          48 :   return 0;
     336             : #endif /*!HAVE_W32_SYSTEM*/
     337             : }
     338             : 
     339             : 
     340             : /* Unlock the spawning process.  */
     341             : static void
     342          48 : unlock_spawning (lock_spawn_t *lock, const char *name)
     343             : {
     344          48 :   if (*lock)
     345             :     {
     346             : #ifdef HAVE_W32_SYSTEM
     347             :       if (!ReleaseMutex (*lock))
     348             :         log_error ("failed to release the spawn_%s mutex: %s\n",
     349             :                    name, w32_strerror (-1));
     350             :       CloseHandle (*lock);
     351             : #else /*!HAVE_W32_SYSTEM*/
     352             :       (void)name;
     353          48 :       dotlock_destroy (*lock);
     354             : #endif /*!HAVE_W32_SYSTEM*/
     355          48 :       *lock = NULL;
     356             :     }
     357          48 : }
     358             : 
     359             : /* Try to connect to the agent via socket or start it if it is not
     360             :    running and AUTOSTART is set.  Handle the server's initial
     361             :    greeting.  Returns a new assuan context at R_CTX or an error
     362             :    code. */
     363             : gpg_error_t
     364         527 : start_new_gpg_agent (assuan_context_t *r_ctx,
     365             :                      gpg_err_source_t errsource,
     366             :                      const char *agent_program,
     367             :                      const char *opt_lc_ctype,
     368             :                      const char *opt_lc_messages,
     369             :                      session_env_t session_env,
     370             :                      int autostart, int verbose, int debug,
     371             :                      gpg_error_t (*status_cb)(ctrl_t, int, ...),
     372             :                      ctrl_t status_cb_arg)
     373             : {
     374             :   gpg_error_t err;
     375             :   assuan_context_t ctx;
     376         527 :   int did_success_msg = 0;
     377             :   char *sockname;
     378             :   const char *argv[6];
     379             : 
     380         527 :   *r_ctx = NULL;
     381             : 
     382         527 :   err = assuan_new (&ctx);
     383         527 :   if (err)
     384             :     {
     385           0 :       log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
     386           0 :       return err;
     387             :     }
     388             : 
     389         527 :   sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
     390         527 :   if (!sockname)
     391             :     {
     392           0 :       err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
     393           0 :       assuan_release (ctx);
     394           0 :       return err;
     395             :     }
     396             : 
     397         527 :   err = assuan_socket_connect (ctx, sockname, 0, 0);
     398         527 :   if (err && autostart)
     399             :     {
     400             :       char *abs_homedir;
     401             :       lock_spawn_t lock;
     402          48 :       char *program = NULL;
     403          48 :       const char *program_arg = NULL;
     404             :       char *p;
     405             :       const char *s;
     406             :       int i;
     407             : 
     408             :       /* With no success start a new server.  */
     409          48 :       if (!agent_program || !*agent_program)
     410           0 :         agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
     411          48 :       else if ((s=strchr (agent_program, '|')) && s[1] == '-' && s[2]=='-')
     412             :         {
     413             :           /* Hack to insert an additional option on the command line.  */
     414          48 :           program = xtrystrdup (agent_program);
     415          48 :           if (!program)
     416             :             {
     417           0 :               gpg_error_t tmperr = gpg_err_make (errsource,
     418             :                                                  gpg_err_code_from_syserror ());
     419           0 :               xfree (sockname);
     420           0 :               assuan_release (ctx);
     421           0 :               return tmperr;
     422             :             }
     423          48 :           p = strchr (program, '|');
     424          48 :           *p++ = 0;
     425          48 :           program_arg = p;
     426             :         }
     427             : 
     428          48 :       if (verbose)
     429          41 :         log_info (_("no running gpg-agent - starting '%s'\n"),
     430             :                   agent_program);
     431             : 
     432          48 :       if (status_cb)
     433           0 :         status_cb (status_cb_arg, STATUS_PROGRESS,
     434             :                    "starting_agent ? 0 0", NULL);
     435             : 
     436             :       /* We better pass an absolute home directory to the agent just
     437             :          in case gpg-agent does not convert the passed name to an
     438             :          absolute one (which it should do).  */
     439          48 :       abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
     440          48 :       if (!abs_homedir)
     441             :         {
     442           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     443             :                                              gpg_err_code_from_syserror ());
     444           0 :           log_error ("error building filename: %s\n",gpg_strerror (tmperr));
     445           0 :           xfree (sockname);
     446           0 :           assuan_release (ctx);
     447           0 :           xfree (program);
     448           0 :           return tmperr;
     449             :         }
     450             : 
     451          48 :       if (fflush (NULL))
     452             :         {
     453           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     454             :                                              gpg_err_code_from_syserror ());
     455           0 :           log_error ("error flushing pending output: %s\n",
     456           0 :                      strerror (errno));
     457           0 :           xfree (sockname);
     458           0 :           assuan_release (ctx);
     459           0 :           xfree (abs_homedir);
     460           0 :           xfree (program);
     461           0 :           return tmperr;
     462             :         }
     463             : 
     464             :       /* If the agent has been configured for use with a standard
     465             :          socket, an environment variable is not required and thus
     466             :          we we can savely start the agent here.  */
     467          48 :       i = 0;
     468          48 :       argv[i++] = "--homedir";
     469          48 :       argv[i++] = abs_homedir;
     470          48 :       argv[i++] = "--use-standard-socket";
     471          48 :       if (program_arg)
     472          48 :         argv[i++] = program_arg;
     473          48 :       argv[i++] = "--daemon";
     474          48 :       argv[i++] = NULL;
     475             : 
     476          48 :       if (!(err = lock_spawning (&lock, gnupg_homedir (), "agent", verbose))
     477          48 :           && assuan_socket_connect (ctx, sockname, 0, 0))
     478             :         {
     479          48 :           err = gnupg_spawn_process_detached (program? program : agent_program,
     480             :                                               argv, NULL);
     481          48 :           if (err)
     482           0 :             log_error ("failed to start agent '%s': %s\n",
     483             :                        agent_program, gpg_strerror (err));
     484             :           else
     485             :             {
     486          48 :               for (i=0; i < SECS_TO_WAIT_FOR_AGENT; i++)
     487             :                 {
     488          48 :                   if (verbose)
     489          41 :                     log_info (_("waiting for the agent to come up ... (%ds)\n"),
     490             :                               SECS_TO_WAIT_FOR_AGENT - i);
     491          48 :                   gnupg_sleep (1);
     492          48 :                   err = assuan_socket_connect (ctx, sockname, 0, 0);
     493          48 :                   if (!err)
     494             :                     {
     495          48 :                       if (verbose)
     496             :                         {
     497          41 :                           log_info (_("connection to agent established\n"));
     498          41 :                           did_success_msg = 1;
     499             :                         }
     500          48 :                       break;
     501             :                     }
     502             :                 }
     503             :             }
     504             :         }
     505             : 
     506          48 :       unlock_spawning (&lock, "agent");
     507          48 :       xfree (abs_homedir);
     508          48 :       xfree (program);
     509             :     }
     510         527 :   xfree (sockname);
     511         527 :   if (err)
     512             :     {
     513           0 :       if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
     514           0 :         log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
     515           0 :       assuan_release (ctx);
     516           0 :       return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
     517             :     }
     518             : 
     519         527 :   if (debug && !did_success_msg)
     520           0 :     log_debug ("connection to agent established\n");
     521             : 
     522         527 :   err = assuan_transact (ctx, "RESET",
     523             :                          NULL, NULL, NULL, NULL, NULL, NULL);
     524         527 :   if (!err)
     525             :     {
     526         527 :       err = send_pinentry_environment (ctx, errsource,
     527             :                                        opt_lc_ctype, opt_lc_messages,
     528             :                                        session_env);
     529         527 :       if (gpg_err_code (err) == GPG_ERR_FORBIDDEN
     530           0 :           && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT)
     531             :         {
     532             :           /* Check whether we are in restricted mode.  */
     533           0 :           if (!assuan_transact (ctx, "GETINFO restricted",
     534             :                                 NULL, NULL, NULL, NULL, NULL, NULL))
     535             :             {
     536           0 :               if (verbose)
     537           0 :                 log_info (_("connection to agent is in restricted mode\n"));
     538           0 :               err = 0;
     539             :             }
     540             :         }
     541             :     }
     542         527 :   if (err)
     543             :     {
     544           0 :       assuan_release (ctx);
     545           0 :       return err;
     546             :     }
     547             : 
     548         527 :   *r_ctx = ctx;
     549         527 :   return 0;
     550             : }
     551             : 
     552             : 
     553             : /* Try to connect to the dirmngr via a socket.  On platforms
     554             :    supporting it, start it up if needed and if AUTOSTART is true.
     555             :    Returns a new assuan context at R_CTX or an error code. */
     556             : gpg_error_t
     557           0 : start_new_dirmngr (assuan_context_t *r_ctx,
     558             :                    gpg_err_source_t errsource,
     559             :                    const char *dirmngr_program,
     560             :                    int autostart,
     561             :                    int verbose, int debug,
     562             :                    gpg_error_t (*status_cb)(ctrl_t, int, ...),
     563             :                    ctrl_t status_cb_arg)
     564             : {
     565             :   gpg_error_t err;
     566             :   assuan_context_t ctx;
     567             :   const char *sockname;
     568           0 :   int did_success_msg = 0;
     569             : 
     570           0 :   *r_ctx = NULL;
     571             : 
     572           0 :   err = assuan_new (&ctx);
     573           0 :   if (err)
     574             :     {
     575           0 :       log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
     576           0 :       return err;
     577             :     }
     578             : 
     579           0 :   sockname = dirmngr_socket_name ();
     580           0 :   err = assuan_socket_connect (ctx, sockname, 0, 0);
     581             : 
     582             : #ifdef USE_DIRMNGR_AUTO_START
     583           0 :   if (err && autostart)
     584             :     {
     585             :       lock_spawn_t lock;
     586             :       const char *argv[4];
     587             :       char *abs_homedir;
     588             : 
     589             :       /* No connection: Try start a new Dirmngr.  */
     590           0 :       if (!dirmngr_program || !*dirmngr_program)
     591           0 :         dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
     592             : 
     593           0 :       if (verbose)
     594           0 :         log_info (_("no running Dirmngr - starting '%s'\n"),
     595             :                   dirmngr_program);
     596             : 
     597           0 :       if (status_cb)
     598           0 :         status_cb (status_cb_arg, STATUS_PROGRESS,
     599             :                    "starting_dirmngr ? 0 0", NULL);
     600             : 
     601           0 :       abs_homedir = make_absfilename (gnupg_homedir (), NULL);
     602           0 :       if (!abs_homedir)
     603             :         {
     604           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     605             :                                              gpg_err_code_from_syserror ());
     606           0 :           log_error ("error building filename: %s\n",gpg_strerror (tmperr));
     607           0 :           assuan_release (ctx);
     608           0 :           return tmperr;
     609             :         }
     610             : 
     611           0 :       if (fflush (NULL))
     612             :         {
     613           0 :           gpg_error_t tmperr = gpg_err_make (errsource,
     614             :                                              gpg_err_code_from_syserror ());
     615           0 :           log_error ("error flushing pending output: %s\n",
     616           0 :                      strerror (errno));
     617           0 :           assuan_release (ctx);
     618           0 :           return tmperr;
     619             :         }
     620             : 
     621           0 :       argv[0] = "--daemon";
     622             :       /* Try starting the daemon.  Versions of dirmngr < 2.1.15 do
     623             :        * this only if the home directory is given on the command line.  */
     624           0 :       argv[1] = "--homedir";
     625           0 :       argv[2] = abs_homedir;
     626           0 :       argv[3] = NULL;
     627             : 
     628           0 :       if (!(err = lock_spawning (&lock, gnupg_homedir (), "dirmngr", verbose))
     629           0 :           && assuan_socket_connect (ctx, sockname, 0, 0))
     630             :         {
     631           0 :           err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL);
     632           0 :           if (err)
     633           0 :             log_error ("failed to start the dirmngr '%s': %s\n",
     634             :                        dirmngr_program, gpg_strerror (err));
     635             :           else
     636             :             {
     637             :               int i;
     638             : 
     639           0 :               for (i=0; i < SECS_TO_WAIT_FOR_DIRMNGR; i++)
     640             :                 {
     641           0 :                   if (verbose)
     642           0 :                     log_info (_("waiting for the dirmngr "
     643             :                                 "to come up ... (%ds)\n"),
     644             :                               SECS_TO_WAIT_FOR_DIRMNGR - i);
     645           0 :                   gnupg_sleep (1);
     646           0 :                   err = assuan_socket_connect (ctx, sockname, 0, 0);
     647           0 :                   if (!err)
     648             :                     {
     649           0 :                       if (verbose)
     650             :                         {
     651           0 :                           log_info (_("connection to the dirmngr"
     652             :                                       " established\n"));
     653           0 :                           did_success_msg = 1;
     654             :                         }
     655           0 :                       break;
     656             :                     }
     657             :                 }
     658             :             }
     659             :         }
     660             : 
     661           0 :       unlock_spawning (&lock, "dirmngr");
     662           0 :       xfree (abs_homedir);
     663             :     }
     664             : #else
     665             :   (void)dirmngr_program;
     666             :   (void)verbose;
     667             :   (void)status_cb;
     668             :   (void)status_cb_arg;
     669             : #endif /*USE_DIRMNGR_AUTO_START*/
     670             : 
     671           0 :   if (err)
     672             :     {
     673           0 :       if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
     674           0 :         log_error ("connecting dirmngr at '%s' failed: %s\n",
     675             :                    sockname, gpg_strerror (err));
     676           0 :       assuan_release (ctx);
     677           0 :       return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
     678             :     }
     679             : 
     680           0 :   if (debug && !did_success_msg)
     681           0 :     log_debug ("connection to the dirmngr established\n");
     682             : 
     683           0 :   *r_ctx = ctx;
     684           0 :   return 0;
     685             : }
     686             : 
     687             : 
     688             : /* Return the version of a server using "GETINFO version".  On success
     689             :    0 is returned and R_VERSION receives a malloced string with the
     690             :    version which must be freed by the caller.  On error NULL is stored
     691             :    at R_VERSION and an error code returned.  Mode is in general 0 but
     692             :    certian values may be used to modify the used version command:
     693             : 
     694             :       MODE == 0 = Use "GETINFO version"
     695             :       MODE == 2 - Use "SCD GETINFO version"
     696             :  */
     697             : gpg_error_t
     698         446 : get_assuan_server_version (assuan_context_t ctx, int mode, char **r_version)
     699             : {
     700             :   gpg_error_t err;
     701             :   membuf_t data;
     702             : 
     703         446 :   init_membuf (&data, 64);
     704         446 :   err = assuan_transact (ctx,
     705             :                          mode == 2? "SCD GETINFO version"
     706             :                          /**/     : "GETINFO version",
     707             :                          put_membuf_cb, &data,
     708             :                          NULL, NULL, NULL, NULL);
     709         446 :   if (err)
     710             :     {
     711           0 :       xfree (get_membuf (&data, NULL));
     712           0 :       *r_version = NULL;
     713             :     }
     714             :   else
     715             :     {
     716         446 :       put_membuf (&data, "", 1);
     717         446 :       *r_version = get_membuf (&data, NULL);
     718         446 :       if (!*r_version)
     719           0 :         err = gpg_error_from_syserror ();
     720             :     }
     721         446 :   return err;
     722             : }

Generated by: LCOV version 1.11