Coverage Report

Created: 2026-02-26 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/asshelp.c
Line
Count
Source
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 "sysutils.h"
43
#include "status.h"
44
#include "membuf.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
0
# 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
4
#define SECS_TO_WAIT_FOR_AGENT 8
57
0
#define SECS_TO_WAIT_FOR_KEYBOXD 8
58
0
#define SECS_TO_WAIT_FOR_DIRMNGR 8
59
60
/* A bitfield that specifies the assuan categories to log.  This is
61
   identical to the default log handler of libassuan.  We need to do
62
   it ourselves because we use a custom log handler and want to use
63
   the same assuan variables to select the categories to log. */
64
static int log_cats;
65
0
#define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1))))
66
67
/* The assuan log monitor used to temporary inhibit log messages from
68
 * assuan.  */
69
static int (*my_log_monitor) (assuan_context_t ctx,
70
                              unsigned int cat,
71
                              const char *msg);
72
73
74
static int
75
my_libassuan_log_handler (assuan_context_t ctx, void *hook,
76
                          unsigned int cat, const char *msg)
77
0
{
78
0
  unsigned int dbgval;
79
80
0
  if (! TEST_LOG_CAT (cat))
81
0
    return 0;
82
83
0
  dbgval = hook? *(unsigned int*)hook : 0;
84
0
  if (!(dbgval & 1024))
85
0
    return 0; /* Assuan debugging is not enabled.  */
86
87
0
  if (ctx && my_log_monitor && !my_log_monitor (ctx, cat, msg))
88
0
    return 0; /* Temporary disabled.  */
89
90
0
  if (msg)
91
0
    log_string (GPGRT_LOGLVL_DEBUG, msg);
92
93
0
  return 1;
94
0
}
95
96
97
/* Setup libassuan to use our own logging functions.  Should be used
98
   early at startup.  */
99
void
100
setup_libassuan_logging (unsigned int *debug_var_address,
101
                         int (*log_monitor)(assuan_context_t ctx,
102
                                            unsigned int cat,
103
                                            const char *msg))
104
0
{
105
0
  char *flagstr;
106
107
0
  flagstr = getenv ("ASSUAN_DEBUG");
108
0
  if (flagstr)
109
0
    log_cats = atoi (flagstr);
110
0
  else /* Default to log the control channel.  */
111
0
    log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
112
0
  my_log_monitor = log_monitor;
113
0
  assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
114
0
}
115
116
117
/* Change the Libassuan log categories to those given by NEWCATS.
118
   NEWCATS is 0 the default category of ASSUAN_LOG_CONTROL is
119
   selected.  Note, that setup_libassuan_logging overrides the values
120
   given here.  */
121
void
122
set_libassuan_log_cats (unsigned int newcats)
123
0
{
124
0
  if (newcats)
125
0
    log_cats = newcats;
126
0
  else /* Default to log the control channel.  */
127
0
    log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
128
0
}
129
130
131
/* Get the last Windows error from an Assuan socket function and print
132
 * the raw error code using log_info.  */
133
void
134
log_libassuan_system_error (assuan_fd_t fd)
135
0
{
136
0
  int w32err = 0;
137
138
0
  if (assuan_sock_get_flag (fd, "w32_error", &w32err))
139
0
    w32err = -1;  /* Old Libassuan or not Windows.  */
140
141
0
  if (w32err != -1)
142
0
    log_info ("system error code: %d (0x%x)\n", w32err, w32err);
143
0
}
144
145
146
147
static gpg_error_t
148
send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
149
                 const char *name, const char *value, int use_putenv)
150
0
{
151
0
  gpg_error_t err;
152
0
  char *optstr;
153
154
0
  (void)errsource;
155
156
0
  if (!value || !*value)
157
0
    err = 0;  /* Avoid sending empty strings.  */
158
0
  else if (asprintf (&optstr, "OPTION %s%s=%s",
159
0
                     use_putenv? "putenv=":"", name, value) < 0)
160
0
    err = gpg_error_from_syserror ();
161
0
  else
162
0
    {
163
0
      err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
164
0
      xfree (optstr);
165
0
    }
166
167
0
  return err;
168
0
}
169
170
171
/* Send the assuan commands pertaining to the pinentry environment.  The
172
   OPT_* arguments are optional and may be used to override the
173
   defaults taken from the current locale. */
174
gpg_error_t
175
send_pinentry_environment (assuan_context_t ctx,
176
                           gpg_err_source_t errsource,
177
                           const char *opt_lc_ctype,
178
                           const char *opt_lc_messages,
179
                           session_env_t session_env)
180
181
0
{
182
0
  gpg_error_t err = 0;
183
0
#if defined(HAVE_SETLOCALE)
184
0
  char *old_lc = NULL;
185
0
#endif
186
0
  char *dft_lc = NULL;
187
0
  const char *dft_ttyname;
188
0
  int iterator;
189
0
  const char *name, *assname, *value;
190
0
  int is_default;
191
192
0
  iterator = 0;
193
0
  while ((name = session_env_list_stdenvnames (&iterator, &assname)))
194
0
    {
195
0
      value = session_env_getenv_or_default (session_env, name, NULL);
196
0
      if (!value)
197
0
        continue;
198
199
0
      if (assname)
200
0
        err = send_one_option (ctx, errsource, assname, value, 0);
201
0
      else
202
0
        {
203
0
          err = send_one_option (ctx, errsource, name, value, 1);
204
0
          if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
205
0
            err = 0;  /* Server too old; can't pass the new envvars.  */
206
0
        }
207
0
      if (err)
208
0
        return err;
209
0
    }
210
211
212
0
  dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY",
213
0
                                               &is_default);
214
0
  if (dft_ttyname && !is_default)
215
0
    dft_ttyname = NULL;  /* We need the default value.  */
216
217
  /* Send the value for LC_CTYPE.  */
218
0
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
219
0
  old_lc = setlocale (LC_CTYPE, NULL);
220
0
  if (old_lc)
221
0
    {
222
0
      old_lc = xtrystrdup (old_lc);
223
0
      if (!old_lc)
224
0
        return gpg_error_from_syserror ();
225
0
    }
226
0
  dft_lc = setlocale (LC_CTYPE, "");
227
0
#endif
228
0
  if (opt_lc_ctype || (dft_ttyname && dft_lc))
229
0
    {
230
0
      err = send_one_option (ctx, errsource, "lc-ctype",
231
0
                             opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
232
0
    }
233
0
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
234
0
  if (old_lc)
235
0
    {
236
0
      setlocale (LC_CTYPE, old_lc);
237
0
      xfree (old_lc);
238
0
    }
239
0
#endif
240
0
  if (err)
241
0
    return err;
242
243
  /* Send the value for LC_MESSAGES.  */
244
0
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
245
0
  old_lc = setlocale (LC_MESSAGES, NULL);
246
0
  if (old_lc)
247
0
    {
248
0
      old_lc = xtrystrdup (old_lc);
249
0
      if (!old_lc)
250
0
        return gpg_error_from_syserror ();
251
0
    }
252
0
  dft_lc = setlocale (LC_MESSAGES, "");
253
0
#endif
254
0
  if (opt_lc_messages || (dft_ttyname && dft_lc))
255
0
    {
256
0
      err = send_one_option (ctx, errsource, "lc-messages",
257
0
                             opt_lc_messages ? opt_lc_messages : dft_lc, 0);
258
0
    }
259
0
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
260
0
  if (old_lc)
261
0
    {
262
0
      setlocale (LC_MESSAGES, old_lc);
263
0
      xfree (old_lc);
264
0
    }
265
0
#endif
266
0
  if (err)
267
0
    return err;
268
269
0
  return 0;
270
0
}
271
272
273
/* Lock a spawning process.  The caller needs to provide the address
274
   of a variable to store the lock information and the name or the
275
   process.  */
276
static gpg_error_t
277
lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name,
278
               int verbose)
279
0
{
280
0
  char *fname;
281
0
  (void)verbose;
282
283
0
  *lock = NULL;
284
285
0
  fname = make_absfilename_try
286
0
    (homedir,
287
0
     !strcmp (name, "agent")?   "gnupg_spawn_agent_sentinel":
288
0
     !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
289
0
     !strcmp (name, "keyboxd")? "gnupg_spawn_keyboxd_sentinel":
290
0
     /*                    */   "gnupg_spawn_unknown_sentinel",
291
0
     NULL);
292
0
  if (!fname)
293
0
    return gpg_error_from_syserror ();
294
295
0
  *lock = dotlock_create (fname, 0);
296
0
  xfree (fname);
297
0
  if (!*lock)
298
0
    return gpg_error_from_syserror ();
299
300
  /* FIXME: We should use a timeout of 5000 here - however
301
     make_dotlock does not yet support values other than -1 and 0.  */
302
0
  if (dotlock_take (*lock, -1))
303
0
    return gpg_error_from_syserror ();
304
305
0
  return 0;
306
0
}
307
308
309
/* Unlock the spawning process.  */
310
static void
311
unlock_spawning (lock_spawn_t *lock, const char *name)
312
0
{
313
0
  if (*lock)
314
0
    {
315
0
      (void)name;
316
0
      dotlock_destroy (*lock);
317
0
      *lock = NULL;
318
0
    }
319
0
}
320
321
322
/* Helper to start a service.  SECS gives the number of seconds to
323
 * wait.  SOCKNAME is the name of the socket to connect.  VERBOSE is
324
 * the usual verbose flag.  CTX is the assuan context.  CONNECT_FLAGS
325
 * are the assuan connect flags.  DID_SUCCESS_MSG will be set to 1 if
326
 * a success messages has been printed.
327
 */
328
static gpg_error_t
329
wait_for_sock (int secs, int module_name_id, const char *sockname,
330
               unsigned int connect_flags,
331
               int verbose, assuan_context_t ctx, int *did_success_msg)
332
0
{
333
0
  gpg_error_t err = 0;
334
0
  int target_us = secs * 1000000;
335
0
  int elapsed_us = 0;
336
  /*
337
   * 977us * 1024 = just a little more than 1s.
338
   * so we will double this timeout 10 times in the first
339
   * second, and then switch over to 1s checkins.
340
   */
341
0
  int next_sleep_us = 977;
342
0
  int lastalert = secs+1;
343
0
  int secsleft;
344
345
0
  while (elapsed_us < target_us)
346
0
    {
347
0
      if (verbose)
348
0
        {
349
0
          secsleft = (target_us - elapsed_us + 999999)/1000000;
350
          /* log_clock ("left=%d last=%d targ=%d elap=%d next=%d\n", */
351
          /*            secsleft, lastalert, target_us, elapsed_us, */
352
          /*            next_sleep_us); */
353
0
          if (secsleft < lastalert)
354
0
            {
355
0
              log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR?
356
0
                        _("waiting for the dirmngr to come up ... (%ds)\n"):
357
0
                        module_name_id == GNUPG_MODULE_NAME_KEYBOXD?
358
0
                        _("waiting for the keyboxd to come up ... (%ds)\n"):
359
0
                        _("waiting for the agent to come up ... (%ds)\n"),
360
0
                        secsleft);
361
0
              lastalert = secsleft;
362
0
            }
363
0
        }
364
0
      gnupg_usleep (next_sleep_us);
365
0
      elapsed_us += next_sleep_us;
366
0
      err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
367
0
      if (!err)
368
0
        {
369
0
          if (verbose)
370
0
            {
371
0
              log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR?
372
0
                        _("connection to the dirmngr established\n"):
373
0
                        module_name_id == GNUPG_MODULE_NAME_KEYBOXD?
374
0
                        _("connection to the keyboxd established\n"):
375
0
                        _("connection to the agent established\n"));
376
0
              *did_success_msg = 1;
377
0
            }
378
0
          break;
379
0
        }
380
0
      next_sleep_us *= 2;
381
0
      if (next_sleep_us > 1000000)
382
0
        next_sleep_us = 1000000;
383
0
    }
384
0
  return err;
385
0
}
386
387
388
/* Try to connect to a new service via socket or start it if it is not
389
 * running and AUTOSTART is set.  Handle the server's initial
390
 * greeting.  Returns a new assuan context at R_CTX or an error code.
391
 * MODULE_NAME_ID is one of:
392
 *     GNUPG_MODULE_NAME_AGENT
393
 *     GNUPG_MODULE_NAME_DIRMNGR
394
 */
395
static gpg_error_t
396
start_new_service (assuan_context_t *r_ctx,
397
                   int module_name_id,
398
                   gpg_err_source_t errsource,
399
                   const char *program_name,
400
                   const char *opt_lc_ctype,
401
                   const char *opt_lc_messages,
402
                   session_env_t session_env,
403
                   unsigned int flags,
404
                   int verbose, int debug,
405
                   gpg_error_t (*status_cb)(ctrl_t, int, ...),
406
                   ctrl_t status_cb_arg)
407
4
{
408
4
  gpg_error_t err;
409
4
  assuan_context_t ctx;
410
4
  int did_success_msg = 0;
411
4
  char *sockname;
412
4
  const char *printed_name;
413
4
  const char *lock_name;
414
4
  const char *status_start_line;
415
4
  int no_service_err;
416
4
  int seconds_to_wait;
417
4
  unsigned int connect_flags = 0;
418
4
  const char *argv[6];
419
420
4
  *r_ctx = NULL;
421
422
4
  err = assuan_new (&ctx);
423
4
  if (err)
424
0
    {
425
0
      log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
426
0
      return err;
427
0
    }
428
429
4
  switch (module_name_id)
430
4
    {
431
4
    case GNUPG_MODULE_NAME_AGENT:
432
4
      sockname = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
433
4
      lock_name = "agent";
434
4
      printed_name = "gpg-agent";
435
4
      status_start_line = "starting_agent ? 0 0";
436
4
      no_service_err = GPG_ERR_NO_AGENT;
437
4
      seconds_to_wait = SECS_TO_WAIT_FOR_AGENT;
438
4
      break;
439
0
    case GNUPG_MODULE_NAME_DIRMNGR:
440
0
      sockname = make_filename (gnupg_socketdir (), DIRMNGR_SOCK_NAME, NULL);
441
0
      lock_name = "dirmngr";
442
0
      printed_name = "dirmngr";
443
0
      status_start_line = "starting_dirmngr ? 0 0";
444
0
      no_service_err = GPG_ERR_NO_DIRMNGR;
445
0
      seconds_to_wait = SECS_TO_WAIT_FOR_DIRMNGR;
446
0
      break;
447
0
    case GNUPG_MODULE_NAME_KEYBOXD:
448
0
      sockname = make_filename (gnupg_socketdir (), KEYBOXD_SOCK_NAME, NULL);
449
0
      lock_name = "keyboxd";
450
0
      printed_name = "keyboxd";
451
0
      status_start_line = "starting_keyboxd ? 0 0";
452
0
      no_service_err = GPG_ERR_NO_KEYBOXD;
453
0
      seconds_to_wait = SECS_TO_WAIT_FOR_KEYBOXD;
454
0
      connect_flags |= ASSUAN_SOCKET_CONNECT_FDPASSING;
455
0
      break;
456
0
    default:
457
0
      err = gpg_error (GPG_ERR_INV_ARG);
458
0
      assuan_release (ctx);
459
0
      return err;
460
4
    }
461
462
4
  err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
463
4
  if (err && (flags & ASSHELP_FLAG_AUTOSTART))
464
0
    {
465
0
      char *abs_homedir;
466
0
      lock_spawn_t lock;
467
0
      char *program = NULL;
468
0
      const char *program_arg = NULL;
469
0
      char *p;
470
0
      const char *s;
471
0
      int i;
472
473
      /* With no success start a new server.  */
474
0
      if (!program_name || !*program_name)
475
0
        program_name = gnupg_module_name (module_name_id);
476
0
      else if ((s=strchr (program_name, '|')) && s[1] == '-' && s[2]=='-')
477
0
        {
478
          /* Hack to insert an additional option on the command line.  */
479
0
          program = xtrystrdup (program_name);
480
0
          if (!program)
481
0
            {
482
0
              gpg_error_t tmperr = gpg_err_make (errsource,
483
0
                                                 gpg_err_code_from_syserror ());
484
0
              xfree (sockname);
485
0
              assuan_release (ctx);
486
0
              return tmperr;
487
0
            }
488
0
          p = strchr (program, '|');
489
0
          *p++ = 0;
490
0
          program_arg = p;
491
0
        }
492
493
0
      if (verbose)
494
0
        log_info (_("no running %s - starting '%s'\n"),
495
0
                  printed_name, program_name);
496
497
0
      if (status_cb)
498
0
        status_cb (status_cb_arg, STATUS_PROGRESS, status_start_line, NULL);
499
500
      /* We better pass an absolute home directory to the service just
501
       * in case the service does not convert the passed name to an
502
       * absolute one (which it should do).  */
503
0
      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
504
0
      if (!abs_homedir)
505
0
        {
506
0
          gpg_error_t tmperr = gpg_err_make (errsource,
507
0
                                             gpg_err_code_from_syserror ());
508
0
          log_error ("error building filename: %s\n", gpg_strerror (tmperr));
509
0
          xfree (sockname);
510
0
          assuan_release (ctx);
511
0
          xfree (program);
512
0
          return tmperr;
513
0
        }
514
515
0
      if (fflush (NULL))
516
0
        {
517
0
          gpg_error_t tmperr = gpg_err_make (errsource,
518
0
                                             gpg_err_code_from_syserror ());
519
0
          log_error ("error flushing pending output: %s\n", strerror (errno));
520
0
          xfree (sockname);
521
0
          assuan_release (ctx);
522
0
          xfree (abs_homedir);
523
0
          xfree (program);
524
0
          return tmperr;
525
0
        }
526
527
0
      i = 0;
528
0
      argv[i++] = "--homedir";
529
0
      argv[i++] = abs_homedir;
530
0
      if (program_arg)
531
0
        argv[i++] = program_arg;
532
0
      argv[i++] = "--daemon";
533
0
      argv[i++] = NULL;
534
535
0
      if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose))
536
0
          && assuan_socket_connect (ctx, sockname, 0, connect_flags))
537
0
        {
538
#ifdef HAVE_W32_SYSTEM
539
          gpgrt_process_t proc;
540
541
          /* On Windows we remove the socketname before creating it.
542
           * This is so that we can wait for a client which is
543
           * currently trying to connect.  The 10000 will make the
544
           * remove function wait up to 10 seconds for sharing
545
           * violation to go away.  */
546
          gnupg_remove_ext (sockname, 10000);
547
          err = gpgrt_process_spawn (program? program : program_name, argv,
548
                                     (GPGRT_PROCESS_DETACHED
549
                                      |GPGRT_PROCESS_STDIO_NUL
550
                                      |GPGRT_PROCESS_STDOUT_PIPE
551
                                      |GPGRT_PROCESS_STDERR_KEEP),
552
                                     NULL, &proc);
553
          if (!err)
554
            {
555
              int pipe_in;
556
              err = gpgrt_process_get_fds (proc, 0, NULL, &pipe_in, NULL);
557
              if (!err)
558
                {
559
                  char buf[256];
560
                  int r;
561
562
                  /* We wait until the child process says it's ready
563
                     to serve, by reading from the pipe.  */
564
                  r = read (pipe_in, buf, sizeof buf);
565
                  close (pipe_in);
566
                  if (r < 0)
567
                    {
568
                      if (verbose)
569
                        log_info ("read from child process failed: %s\n",
570
                                  strerror (errno));
571
                      /*
572
                       * Go ahead, ignoring the read error, so that
573
                       * we can still support older Windows (< Vista).
574
                       *
575
                       * In future, we should return error with
576
                       * GPG_ERR_SERVER_FAILED here.
577
                       */
578
                    }
579
                }
580
              gpgrt_process_release (proc);
581
            }
582
#else /*!W32*/
583
0
          err = gpgrt_process_spawn (program? program : program_name, argv,
584
0
                                     0, NULL, NULL);
585
0
#endif /*!W32*/
586
0
          if (err)
587
0
            log_error ("failed to start %s '%s': %s\n",
588
0
                       printed_name, program? program : program_name,
589
0
                       gpg_strerror (err));
590
0
          else
591
0
            err = wait_for_sock (seconds_to_wait, module_name_id,
592
0
                                 sockname, connect_flags,
593
0
                                 verbose, ctx, &did_success_msg);
594
0
        }
595
596
0
      unlock_spawning (&lock, lock_name);
597
0
      xfree (abs_homedir);
598
0
      xfree (program);
599
0
    }
600
4
  xfree (sockname);
601
4
  if (err)
602
4
    {
603
4
      if ((flags & ASSHELP_FLAG_AUTOSTART)
604
4
          || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
605
4
        log_error ("can't connect to the %s: %s\n",
606
0
                   printed_name, gpg_strerror (err));
607
4
      assuan_release (ctx);
608
4
      return gpg_err_make (errsource, no_service_err);
609
4
    }
610
611
0
  if (debug && !did_success_msg)
612
0
    log_debug ("connection to the %s established\n", printed_name);
613
614
0
  if (module_name_id == GNUPG_MODULE_NAME_AGENT)
615
0
    err = assuan_transact (ctx, "RESET",
616
0
                           NULL, NULL, NULL, NULL, NULL, NULL);
617
618
0
  if (!err
619
0
      && module_name_id == GNUPG_MODULE_NAME_AGENT)
620
0
    {
621
0
      err = send_pinentry_environment (ctx, errsource,
622
0
                                       opt_lc_ctype, opt_lc_messages,
623
0
                                       session_env);
624
0
      if (gpg_err_code (err) == GPG_ERR_FORBIDDEN
625
0
          && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT)
626
0
        {
627
          /* Check whether the agent is in restricted mode.  */
628
0
          if (!assuan_transact (ctx, "GETINFO restricted",
629
0
                                NULL, NULL, NULL, NULL, NULL, NULL))
630
0
            {
631
0
              if (verbose)
632
0
                log_info (_("connection to the agent is in restricted mode\n"));
633
0
              err = 0;
634
0
            }
635
0
        }
636
0
    }
637
0
  if (err)
638
0
    {
639
0
      assuan_release (ctx);
640
0
      return err;
641
0
    }
642
643
0
  *r_ctx = ctx;
644
0
  return 0;
645
0
}
646
647
648
/* Try to connect to the agent or start a new one.  */
649
gpg_error_t
650
start_new_gpg_agent (assuan_context_t *r_ctx,
651
                     gpg_err_source_t errsource,
652
                     const char *agent_program,
653
                     const char *opt_lc_ctype,
654
                     const char *opt_lc_messages,
655
                     session_env_t session_env,
656
                     unsigned int flags,
657
                     int verbose, int debug,
658
                     gpg_error_t (*status_cb)(ctrl_t, int, ...),
659
                     ctrl_t status_cb_arg)
660
4
{
661
4
  return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT,
662
4
                            errsource, agent_program,
663
4
                            opt_lc_ctype, opt_lc_messages, session_env,
664
4
                            flags, verbose, debug,
665
4
                            status_cb, status_cb_arg);
666
4
}
667
668
669
/* Try to connect to the dirmngr via a socket.  On platforms
670
   supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
671
   Returns a new assuan context at R_CTX or an error code. */
672
gpg_error_t
673
start_new_keyboxd (assuan_context_t *r_ctx,
674
                   gpg_err_source_t errsource,
675
                   const char *keyboxd_program,
676
                   unsigned int flags,
677
                   int verbose, int debug,
678
                   gpg_error_t (*status_cb)(ctrl_t, int, ...),
679
                   ctrl_t status_cb_arg)
680
0
{
681
0
  return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD,
682
0
                            errsource, keyboxd_program,
683
0
                            NULL, NULL, NULL,
684
0
                            flags, verbose, debug,
685
0
                            status_cb, status_cb_arg);
686
0
}
687
688
689
/* Try to connect to the dirmngr via a socket.  On platforms
690
   supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
691
   Returns a new assuan context at R_CTX or an error code. */
692
gpg_error_t
693
start_new_dirmngr (assuan_context_t *r_ctx,
694
                   gpg_err_source_t errsource,
695
                   const char *dirmngr_program,
696
                   unsigned int flags,
697
                   int verbose, int debug,
698
                   gpg_error_t (*status_cb)(ctrl_t, int, ...),
699
                   ctrl_t status_cb_arg)
700
0
{
701
#ifndef USE_DIRMNGR_AUTO_START
702
  flags &= ~ASSHELP_FLAG_AUTOSTART;  /* Clear flag.  */
703
#endif
704
0
  return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
705
0
                            errsource, dirmngr_program,
706
0
                            NULL, NULL, NULL,
707
0
                            flags, verbose, debug,
708
0
                            status_cb, status_cb_arg);
709
0
}
710
711
712
/* Return the version of a server using "GETINFO version".  On success
713
   0 is returned and R_VERSION receives a malloced string with the
714
   version which must be freed by the caller.  On error NULL is stored
715
   at R_VERSION and an error code returned.  Mode is in general 0 but
716
   certain values may be used to modify the used version command:
717
718
      MODE == 0 = Use "GETINFO version"
719
      MODE == 2 - Use "SCD GETINFO version"
720
 */
721
gpg_error_t
722
get_assuan_server_version (assuan_context_t ctx, int mode, char **r_version)
723
0
{
724
0
  gpg_error_t err;
725
0
  membuf_t data;
726
727
0
  init_membuf (&data, 64);
728
0
  err = assuan_transact (ctx,
729
0
                         mode == 2? "SCD GETINFO version"
730
0
                         /**/     : "GETINFO version",
731
0
                         put_membuf_cb, &data,
732
0
                         NULL, NULL, NULL, NULL);
733
0
  if (err)
734
0
    {
735
0
      xfree (get_membuf (&data, NULL));
736
0
      *r_version = NULL;
737
0
    }
738
0
  else
739
0
    {
740
0
      put_membuf (&data, "", 1);
741
0
      *r_version = get_membuf (&data, NULL);
742
0
      if (!*r_version)
743
0
        err = gpg_error_from_syserror ();
744
0
    }
745
0
  return err;
746
0
}
747
748
749
/* Print a warning if the server's version number is less than our
750
 * version number.  Returns an error code on a connection problem.
751
 * CTX is the Assuan context, SERVERNAME is the name of the server,
752
 * STATUS_FUNC and STATUS_FUNC_DATA is a callback to emit status
753
 * messages.  If PRINT_HINTS is set additional hints are printed.  For
754
 * MODE see get_assuan_server_version.  */
755
gpg_error_t
756
warn_server_version_mismatch (assuan_context_t ctx,
757
                              const char *servername, int mode,
758
                              gpg_error_t (*status_func)(ctrl_t ctrl,
759
                                                         int status_no,
760
                                                         ...),
761
                              void *status_func_ctrl,
762
                              int print_hints)
763
0
{
764
0
  gpg_error_t err;
765
0
  char *serverversion;
766
0
  const char *myversion = gpgrt_strusage (13);
767
768
0
  err = get_assuan_server_version (ctx, mode, &serverversion);
769
0
  if (err)
770
0
    log_log (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED?
771
0
             GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
772
0
             _("error getting version from '%s': %s\n"),
773
0
             servername, gpg_strerror (err));
774
0
  else if (compare_version_strings (serverversion, myversion) < 0)
775
0
    {
776
0
      char *warn;
777
778
0
      warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
779
0
                           servername, serverversion, myversion);
780
0
      if (!warn)
781
0
        err = gpg_error_from_syserror ();
782
0
      else
783
0
        {
784
0
          log_info (_("WARNING: %s\n"), warn);
785
0
          if (print_hints)
786
0
            {
787
0
              log_info (_("Note: Outdated servers may lack important"
788
0
                          " security fixes.\n"));
789
0
              log_info (_("Note: Use the command \"%s\" to restart them.\n"),
790
0
                        "gpgconf --kill all");
791
0
            }
792
0
          if (status_func)
793
0
            status_func (status_func_ctrl, STATUS_WARNING,
794
0
                         "server_version_mismatch 0", warn, NULL);
795
0
          xfree (warn);
796
0
        }
797
0
    }
798
0
  xfree (serverversion);
799
0
  return err;
800
0
}
801
802
803
#ifdef HAVE_W32_SYSTEM
804
#include <fcntl.h>
805
806
/*
807
 * At the start of service (gpg-agent/dirmngr/keyboxd), after the
808
 * preparation of socket, send "OK" (or "ERR 1") to the frontend
809
 * (gpg/gpgsm).
810
 */
811
void
812
w32_ack_to_frontend (void)
813
{
814
  int null_fd = open ("NUL", O_RDWR);
815
816
  /* For the case of older Windows (< Vista), stdin/stdout/stder is
817
   * invalid handle and write to stdout may fail.  We ignore this
818
   * error.  */
819
  if (null_fd < 0)
820
    {
821
      perror ("open failed");
822
      /* Reply "General Error".  */
823
      write (1, "ERR 1\n", 6);
824
    }
825
  else
826
    {
827
      /* Reply, it's OK (because it's ready to serve).  */
828
      write (1, "OK\n", 3);
829
      if (dup2 (null_fd, 1) < 0)
830
        perror ("dup2 failed");
831
      dup2 (null_fd, 2);
832
      close (null_fd);
833
    }
834
}
835
#endif