~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to sm/call-dirmngr.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* call-dirmngr.c - communication with the dromngr 
 
2
 *      Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
3
 *
 
4
 * This file is part of GnuPG.
 
5
 *
 
6
 * GnuPG is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * GnuPG is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <errno.h>
 
26
#include <unistd.h> 
 
27
#include <time.h>
 
28
#include <assert.h>
 
29
#include <ctype.h>
 
30
 
 
31
#include "gpgsm.h"
 
32
#include <gcrypt.h>
 
33
#include <assuan.h>
 
34
 
 
35
#include "i18n.h"
 
36
#include "keydb.h"
 
37
 
 
38
/* The name of the socket for a system daemon.  */
 
39
#define DEFAULT_SOCKET_NAME "/var/run/dirmngr/socket"
 
40
 
 
41
struct membuf {
 
42
  size_t len;
 
43
  size_t size;
 
44
  char *buf;
 
45
  int out_of_core;
 
46
};
 
47
 
 
48
 
 
49
 
 
50
static ASSUAN_CONTEXT dirmngr_ctx = NULL;
 
51
static int force_pipe_server = 0;
 
52
 
 
53
struct inq_certificate_parm_s {
 
54
  ASSUAN_CONTEXT ctx;
 
55
  ksba_cert_t cert;
 
56
  ksba_cert_t issuer_cert;
 
57
};
 
58
 
 
59
struct isvalid_status_parm_s {
 
60
  CTRL ctrl;
 
61
  int seen;
 
62
  unsigned char fpr[20];
 
63
};
 
64
 
 
65
 
 
66
struct lookup_parm_s {
 
67
  CTRL ctrl;
 
68
  ASSUAN_CONTEXT ctx;
 
69
  void (*cb)(void *, ksba_cert_t);
 
70
  void *cb_value;
 
71
  struct membuf data;
 
72
  int error;
 
73
};
 
74
 
 
75
struct run_command_parm_s {
 
76
  ASSUAN_CONTEXT ctx;
 
77
};
 
78
 
 
79
 
 
80
/* A simple implementation of a dynamic buffer.  Use init_membuf() to
 
81
   create a buffer, put_membuf to append bytes and get_membuf to
 
82
   release and return the buffer.  Allocation errors are detected but
 
83
   only returned at the final get_membuf(), this helps not to clutter
 
84
   the code with out of core checks.  */
 
85
 
 
86
static void
 
87
init_membuf (struct membuf *mb, int initiallen)
 
88
{
 
89
  mb->len = 0;
 
90
  mb->size = initiallen;
 
91
  mb->out_of_core = 0;
 
92
  mb->buf = xtrymalloc (initiallen);
 
93
  if (!mb->buf)
 
94
      mb->out_of_core = 1;
 
95
}
 
96
 
 
97
static void
 
98
put_membuf (struct membuf *mb, const void *buf, size_t len)
 
99
{
 
100
  if (mb->out_of_core)
 
101
    return;
 
102
 
 
103
  if (mb->len + len >= mb->size)
 
104
    {
 
105
      char *p;
 
106
      
 
107
      mb->size += len + 1024;
 
108
      p = xtryrealloc (mb->buf, mb->size);
 
109
      if (!p)
 
110
        {
 
111
          mb->out_of_core = 1;
 
112
          return;
 
113
        }
 
114
      mb->buf = p;
 
115
    }
 
116
  memcpy (mb->buf + mb->len, buf, len);
 
117
  mb->len += len;
 
118
}
 
119
 
 
120
static void *
 
121
get_membuf (struct membuf *mb, size_t *len)
 
122
{
 
123
  char *p;
 
124
 
 
125
  if (mb->out_of_core)
 
126
    {
 
127
      xfree (mb->buf);
 
128
      mb->buf = NULL;
 
129
      return NULL;
 
130
    }
 
131
 
 
132
  p = mb->buf;
 
133
  *len = mb->len;
 
134
  mb->buf = NULL;
 
135
  mb->out_of_core = 1; /* don't allow a reuse */
 
136
  return p;
 
137
}
 
138
 
 
139
 
 
140
 
 
141
 
 
142
 
 
143
/* Try to connect to the agent via socket or fork it off and work by
 
144
   pipes.  Handle the server's initial greeting */
 
145
static int
 
146
start_dirmngr (void)
 
147
{
 
148
  int rc;
 
149
  char *infostr, *p;
 
150
  ASSUAN_CONTEXT ctx;
 
151
  int try_default = 0;
 
152
 
 
153
  if (dirmngr_ctx)
 
154
    return 0; /* fixme: We need a context for each thread or serialize
 
155
                 the access to the dirmngr */
 
156
  /* Note: if you change this to multiple connections, you also need
 
157
     to take care of the implicit option sending caching. */
 
158
 
 
159
  infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
 
160
  if (opt.prefer_system_dirmngr && !force_pipe_server
 
161
      &&(!infostr || !*infostr))
 
162
    {
 
163
      infostr = DEFAULT_SOCKET_NAME;
 
164
      try_default = 1;
 
165
    }
 
166
  if (!infostr || !*infostr)
 
167
    {
 
168
      const char *pgmname;
 
169
      const char *argv[3];
 
170
      int no_close_list[3];
 
171
      int i;
 
172
 
 
173
      if (opt.verbose)
 
174
        log_info (_("no running dirmngr - starting one\n"));
 
175
      
 
176
      if (fflush (NULL))
 
177
        {
 
178
          gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
 
179
          log_error ("error flushing pending output: %s\n", strerror (errno));
 
180
          return tmperr;
 
181
        }
 
182
 
 
183
      if (!opt.dirmngr_program || !*opt.dirmngr_program)
 
184
        opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
 
185
      if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
 
186
        pgmname = opt.dirmngr_program;
 
187
      else
 
188
        pgmname++;
 
189
 
 
190
      argv[0] = pgmname;
 
191
      argv[1] = "--server";
 
192
      argv[2] = NULL;
 
193
 
 
194
      i=0;
 
195
      if (log_get_fd () != -1)
 
196
        no_close_list[i++] = log_get_fd ();
 
197
      no_close_list[i++] = fileno (stderr);
 
198
      no_close_list[i] = -1;
 
199
 
 
200
      /* connect to the agent and perform initial handshaking */
 
201
      rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
 
202
                                no_close_list);
 
203
    }
 
204
  else
 
205
    {
 
206
      int prot;
 
207
      int pid;
 
208
 
 
209
      infostr = xstrdup (infostr);
 
210
      if (!try_default && *infostr)
 
211
        {
 
212
          if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
 
213
            {
 
214
              log_error (_("malformed DIRMNGR_INFO environment variable\n"));
 
215
              xfree (infostr);
 
216
              force_pipe_server = 1;
 
217
              return start_dirmngr ();
 
218
            }
 
219
          *p++ = 0;
 
220
          pid = atoi (p);
 
221
          while (*p && *p != ':')
 
222
            p++;
 
223
          prot = *p? atoi (p+1) : 0;
 
224
          if (prot != 1)
 
225
            {
 
226
              log_error (_("dirmngr protocol version %d is not supported\n"),
 
227
                         prot);
 
228
              xfree (infostr);
 
229
              force_pipe_server = 1;
 
230
              return start_dirmngr ();
 
231
            }
 
232
        }
 
233
      else
 
234
        pid = -1;
 
235
 
 
236
      rc = assuan_socket_connect (&ctx, infostr, pid);
 
237
      xfree (infostr);
 
238
      if (rc == ASSUAN_Connect_Failed)
 
239
        {
 
240
          log_error (_("can't connect to the dirmngr - trying fall back\n"));
 
241
          force_pipe_server = 1;
 
242
          return start_dirmngr ();
 
243
        }
 
244
    }
 
245
 
 
246
  if (rc)
 
247
    {
 
248
      log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
 
249
      return gpg_error (GPG_ERR_NO_DIRMNGR);
 
250
    }
 
251
  dirmngr_ctx = ctx;
 
252
 
 
253
  if (DBG_ASSUAN)
 
254
    log_debug ("connection to dirmngr established\n");
 
255
  return 0;
 
256
}
 
257
 
 
258
 
 
259
 
 
260
/* Handle a SENDCERT inquiry. */
 
261
static AssuanError
 
262
inq_certificate (void *opaque, const char *line)
 
263
{
 
264
  struct inq_certificate_parm_s *parm = opaque;
 
265
  AssuanError rc;
 
266
  const unsigned char *der;
 
267
  size_t derlen;
 
268
  int issuer_mode = 0;
 
269
 
 
270
  if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
 
271
    {
 
272
      line += 8;
 
273
    }
 
274
  else if (!strncmp (line, "SENDISSUERCERT", 14)
 
275
           && (line[14] == ' ' || !line[14]))
 
276
    {
 
277
      line += 14;
 
278
      issuer_mode = 1;
 
279
    }
 
280
  else
 
281
    {
 
282
      log_error ("unsupported inquiry `%s'\n", line);
 
283
      return ASSUAN_Inquire_Unknown;
 
284
    }
 
285
 
 
286
  if (!*line)
 
287
    { /* Send the current certificate. */
 
288
      der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
 
289
                                 &derlen);
 
290
      if (!der)
 
291
        rc = ASSUAN_Inquire_Error;
 
292
      else
 
293
        rc = assuan_send_data (parm->ctx, der, derlen);
 
294
    }
 
295
  else if (issuer_mode)
 
296
    {
 
297
      log_error ("sending specific issuer certificate back "
 
298
                 "is not yet implemented\n");
 
299
      rc = ASSUAN_Inquire_Error;
 
300
    }
 
301
  else 
 
302
    { /* Send the given certificate. */
 
303
      int err;
 
304
      ksba_cert_t cert;
 
305
 
 
306
 
 
307
      err = gpgsm_find_cert (line, &cert);
 
308
      if (err)
 
309
        {
 
310
          log_error ("certificate not found: %s\n", gpg_strerror (err));
 
311
          rc = ASSUAN_Inquire_Error;
 
312
        }
 
313
      else
 
314
        {
 
315
          der = ksba_cert_get_image (cert, &derlen);
 
316
          if (!der)
 
317
            rc = ASSUAN_Inquire_Error;
 
318
          else
 
319
            rc = assuan_send_data (parm->ctx, der, derlen);
 
320
          ksba_cert_release (cert);
 
321
        }
 
322
    }
 
323
 
 
324
  return rc; 
 
325
}
 
326
 
 
327
 
 
328
/* Take a 20 byte hexencoded string and put it into the the provided
 
329
   20 byte buffer FPR in binary format. */
 
330
static int
 
331
unhexify_fpr (const char *hexstr, unsigned char *fpr)
 
332
{
 
333
  const char *s;
 
334
  int n;
 
335
 
 
336
  for (s=hexstr, n=0; hexdigitp (s); s++, n++)
 
337
    ;
 
338
  if (*s || (n != 40))
 
339
    return 0; /* no fingerprint (invalid or wrong length). */
 
340
  n /= 2;
 
341
  for (s=hexstr, n=0; *s; s += 2, n++)
 
342
    fpr[n] = xtoi_2 (s);
 
343
  return 1; /* okay */
 
344
}
 
345
 
 
346
 
 
347
static assuan_error_t
 
348
isvalid_status_cb (void *opaque, const char *line)
 
349
{
 
350
  struct isvalid_status_parm_s *parm = opaque;
 
351
 
 
352
  if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
 
353
    {
 
354
      if (parm->ctrl)
 
355
        {
 
356
          for (line += 8; *line == ' '; line++)
 
357
            ;
 
358
          if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
 
359
            return ASSUAN_Canceled;
 
360
        }
 
361
    }
 
362
  else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
 
363
      && (line[24]==' ' || !line[24]))
 
364
    {
 
365
      parm->seen++;
 
366
      if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
 
367
        parm->seen++; /* Bumb it to indicate an error. */
 
368
    }
 
369
  return 0;
 
370
}
 
371
 
 
372
 
 
373
 
 
374
 
 
375
/* Call the directory manager to check whether the certificate is valid
 
376
   Returns 0 for valid or usually one of the errors:
 
377
 
 
378
  GPG_ERR_CERTIFICATE_REVOKED
 
379
  GPG_ERR_NO_CRL_KNOWN
 
380
  GPG_ERR_CRL_TOO_OLD
 
381
 
 
382
  With USE_OCSP set to true, the dirmngr is asked to do an OCSP
 
383
  request first.
 
384
 */
 
385
int
 
386
gpgsm_dirmngr_isvalid (ctrl_t ctrl,
 
387
                       ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
 
388
{
 
389
  static int did_options;
 
390
  int rc;
 
391
  char *certid;
 
392
  char line[ASSUAN_LINELENGTH];
 
393
  struct inq_certificate_parm_s parm;
 
394
  struct isvalid_status_parm_s stparm;
 
395
 
 
396
 
 
397
  rc = start_dirmngr ();
 
398
  if (rc)
 
399
    return rc;
 
400
 
 
401
  if (use_ocsp)
 
402
    {
 
403
      certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
 
404
    }
 
405
  else
 
406
    {
 
407
      certid = gpgsm_get_certid (cert);
 
408
      if (!certid)
 
409
        {
 
410
          log_error ("error getting the certificate ID\n");
 
411
          return gpg_error (GPG_ERR_GENERAL);
 
412
        }
 
413
    }
 
414
 
 
415
  if (opt.verbose > 1)
 
416
    {
 
417
      char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
 
418
      log_info ("asking dirmngr about %s%s\n", fpr,
 
419
                use_ocsp? " (using OCSP)":"");
 
420
      xfree (fpr);
 
421
    }
 
422
 
 
423
  parm.ctx = dirmngr_ctx;
 
424
  parm.cert = cert;
 
425
  parm.issuer_cert = issuer_cert;
 
426
 
 
427
  stparm.ctrl = ctrl;
 
428
  stparm.seen = 0;
 
429
  memset (stparm.fpr, 0, 20);
 
430
 
 
431
  /* FIXME: If --disable-crl-checks has been set, we should pass an
 
432
     option to dirmngr, so that no fallback CRL check is done after an
 
433
     ocsp check. */
 
434
 
 
435
  /* It is sufficient to send the options only once because we have
 
436
     one connection per process only. */
 
437
  if (!did_options)
 
438
    {
 
439
      if (opt.force_crl_refresh)
 
440
        assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
 
441
                         NULL, NULL, NULL, NULL, NULL, NULL);
 
442
      did_options = 1;
 
443
    }
 
444
  snprintf (line, DIM(line)-1, "ISVALID %s", certid);
 
445
  line[DIM(line)-1] = 0;
 
446
  xfree (certid);
 
447
 
 
448
  rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
 
449
                        inq_certificate, &parm,
 
450
                        isvalid_status_cb, &stparm);
 
451
  if (opt.verbose > 1)
 
452
    log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
 
453
  rc = map_assuan_err (rc);
 
454
 
 
455
  if (!rc && stparm.seen)
 
456
    {
 
457
      /* Need to also check the certificate validity. */
 
458
      if (stparm.seen != 1)
 
459
        {
 
460
          log_error ("communication problem with dirmngr detected\n");
 
461
          rc = gpg_error (GPG_ERR_INV_CRL);
 
462
        }
 
463
      else
 
464
        {
 
465
          KEYDB_HANDLE kh;
 
466
          ksba_cert_t rspcert = NULL;
 
467
 
 
468
          /* Fixme: First try to get the certificate from the
 
469
             dirmngr's cache - it should be there. */
 
470
          kh = keydb_new (0);
 
471
          if (!kh)
 
472
            rc = gpg_error (GPG_ERR_ENOMEM);
 
473
          if (!rc)
 
474
            rc = keydb_search_fpr (kh, stparm.fpr);
 
475
          if (!rc)
 
476
            rc = keydb_get_cert (kh, &rspcert);
 
477
          if (rc)
 
478
            {
 
479
              log_error ("unable to find the certificate used "
 
480
                         "by the dirmngr: %s\n", gpg_strerror (rc));
 
481
              rc = gpg_error (GPG_ERR_INV_CRL);
 
482
            }
 
483
          keydb_release (kh);
 
484
 
 
485
          if (!rc)
 
486
            {
 
487
              rc = gpgsm_cert_use_ocsp_p (rspcert);
 
488
              if (rc)
 
489
                rc = gpg_error (GPG_ERR_INV_CRL);
 
490
              else
 
491
                {
 
492
                  /* Note, the flag = 1: This avoids checking this
 
493
                     certificate over and over again. */
 
494
                  rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
 
495
                  if (rc)
 
496
                    {
 
497
                      log_error ("invalid certificate used for CRL/OCSP: %s\n",
 
498
                                 gpg_strerror (rc));
 
499
                      rc = gpg_error (GPG_ERR_INV_CRL);
 
500
                    }
 
501
                }
 
502
            }
 
503
          ksba_cert_release (rspcert);
 
504
        }
 
505
    }
 
506
  return rc;
 
507
}
 
508
 
 
509
 
 
510
 
 
511
/* Lookup helpers*/
 
512
static AssuanError
 
513
lookup_cb (void *opaque, const void *buffer, size_t length)
 
514
{
 
515
  struct lookup_parm_s *parm = opaque;
 
516
  size_t len;
 
517
  char *buf;
 
518
  ksba_cert_t cert;
 
519
  int rc;
 
520
 
 
521
  if (parm->error)
 
522
    return 0;
 
523
 
 
524
  if (buffer)
 
525
    {
 
526
      put_membuf (&parm->data, buffer, length);
 
527
      return 0;
 
528
    }
 
529
  /* END encountered - process what we have */
 
530
  buf = get_membuf (&parm->data, &len);
 
531
  if (!buf)
 
532
    {
 
533
      parm->error = gpg_error (GPG_ERR_ENOMEM);
 
534
      return 0;
 
535
    }
 
536
 
 
537
  rc = ksba_cert_new (&cert);
 
538
  if (rc)
 
539
    {
 
540
      parm->error = rc;
 
541
      return 0;
 
542
    }
 
543
  rc = ksba_cert_init_from_mem (cert, buf, len);
 
544
  if (rc)
 
545
    {
 
546
      log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
 
547
    }
 
548
  else
 
549
    {
 
550
      parm->cb (parm->cb_value, cert);
 
551
    }
 
552
 
 
553
  ksba_cert_release (cert);
 
554
  init_membuf (&parm->data, 4096);
 
555
  return 0;
 
556
}
 
557
 
 
558
/* Return a properly escaped pattern from NAMES.  The only error
 
559
   return is NULL to indicate a malloc failure. */
 
560
static char *
 
561
pattern_from_strlist (STRLIST names)
 
562
{
 
563
  STRLIST sl;
 
564
  int n;
 
565
  const char *s;
 
566
  char *pattern, *p;
 
567
 
 
568
  for (n=0, sl=names; sl; sl = sl->next)
 
569
    {
 
570
      for (s=sl->d; *s; s++, n++)
 
571
        {
 
572
          if (*s == '%' || *s == ' ' || *s == '+')
 
573
            n += 2;
 
574
        }
 
575
      n++;
 
576
    }
 
577
 
 
578
  p = pattern = xtrymalloc (n+1);
 
579
  if (!pattern)
 
580
    return NULL;
 
581
 
 
582
  for (n=0, sl=names; sl; sl = sl->next)
 
583
    {
 
584
      for (s=sl->d; *s; s++)
 
585
        {
 
586
          switch (*s)
 
587
            {
 
588
            case '%':
 
589
              *p++ = '%';
 
590
              *p++ = '2';
 
591
              *p++ = '5';
 
592
              break;
 
593
            case ' ':
 
594
              *p++ = '%';
 
595
              *p++ = '2';
 
596
              *p++ = '0';
 
597
              break;
 
598
            case '+':
 
599
              *p++ = '%';
 
600
              *p++ = '2';
 
601
              *p++ = 'B';
 
602
              break;
 
603
            default:
 
604
              *p++ = *s;
 
605
              break;
 
606
            }
 
607
        }
 
608
      *p++ = ' ';
 
609
    }
 
610
  if (p == pattern)
 
611
    *pattern = 0; /* is empty */
 
612
  else
 
613
    p[-1] = '\0'; /* remove trailing blank */
 
614
  
 
615
  return pattern;
 
616
}
 
617
 
 
618
static AssuanError
 
619
lookup_status_cb (void *opaque, const char *line)
 
620
{
 
621
  struct lookup_parm_s *parm = opaque;
 
622
 
 
623
  if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
 
624
    {
 
625
      if (parm->ctrl)
 
626
        {
 
627
          for (line += 8; *line == ' '; line++)
 
628
            ;
 
629
          if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
 
630
            return ASSUAN_Canceled;
 
631
        }
 
632
    }
 
633
  else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
 
634
    {
 
635
      if (parm->ctrl)
 
636
        {
 
637
          for (line +=9; *line == ' '; line++)
 
638
            ;
 
639
          gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
 
640
        }
 
641
    }
 
642
  return 0;
 
643
}
 
644
 
 
645
 
 
646
/* Run the Directroy Managers lookup command using the pattern
 
647
   compiled from the strings given in NAMES.  The caller must provide
 
648
   the callback CB which will be passed cert by cert.  Note that CTRL
 
649
   is optional. */
 
650
int 
 
651
gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
 
652
                      void (*cb)(void*, ksba_cert_t), void *cb_value)
 
653
 
654
  int rc;
 
655
  char *pattern;
 
656
  char line[ASSUAN_LINELENGTH];
 
657
  struct lookup_parm_s parm;
 
658
  size_t len;
 
659
 
 
660
  rc = start_dirmngr ();
 
661
  if (rc)
 
662
    return rc;
 
663
 
 
664
  pattern = pattern_from_strlist (names);
 
665
  if (!pattern)
 
666
    return OUT_OF_CORE (errno);
 
667
  snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
 
668
  line[DIM(line)-1] = 0;
 
669
  xfree (pattern);
 
670
 
 
671
  parm.ctrl = ctrl;
 
672
  parm.ctx = dirmngr_ctx;
 
673
  parm.cb = cb;
 
674
  parm.cb_value = cb_value;
 
675
  parm.error = 0;
 
676
  init_membuf (&parm.data, 4096);
 
677
 
 
678
  rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
 
679
                        NULL, NULL, lookup_status_cb, &parm);
 
680
  xfree (get_membuf (&parm.data, &len));
 
681
  if (rc)
 
682
    return map_assuan_err (rc);
 
683
  return parm.error;
 
684
}
 
685
 
 
686
 
 
687
 
 
688
/* Run Command helpers*/
 
689
 
 
690
/* Fairly simple callback to write all output of dirmngr to stdout. */
 
691
static AssuanError
 
692
run_command_cb (void *opaque, const void *buffer, size_t length)
 
693
{
 
694
  if (buffer)
 
695
    {
 
696
      if ( fwrite (buffer, length, 1, stdout) != 1 )
 
697
        log_error ("error writing to stdout: %s\n", strerror (errno));
 
698
    }
 
699
  return 0;
 
700
}
 
701
 
 
702
/* Handle inquiries from the dirmngr COMMAND. */
 
703
static AssuanError
 
704
run_command_inq_cb (void *opaque, const char *line)
 
705
{
 
706
  struct run_command_parm_s *parm = opaque;
 
707
  AssuanError rc = 0;
 
708
 
 
709
  if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
 
710
    { /* send the given certificate */
 
711
      int err;
 
712
      ksba_cert_t cert;
 
713
      const unsigned char *der;
 
714
      size_t derlen;
 
715
 
 
716
      line += 8;
 
717
      if (!*line)
 
718
        return ASSUAN_Inquire_Error;
 
719
 
 
720
      err = gpgsm_find_cert (line, &cert);
 
721
      if (err)
 
722
        {
 
723
          log_error ("certificate not found: %s\n", gpg_strerror (err));
 
724
          rc = ASSUAN_Inquire_Error;
 
725
        }
 
726
      else
 
727
        {
 
728
          der = ksba_cert_get_image (cert, &derlen);
 
729
          if (!der)
 
730
            rc = ASSUAN_Inquire_Error;
 
731
          else
 
732
            rc = assuan_send_data (parm->ctx, der, derlen);
 
733
          ksba_cert_release (cert);
 
734
        }
 
735
    }
 
736
  else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
 
737
    { /* Simply show the message given in the argument. */
 
738
      line += 9;
 
739
      log_info ("dirmngr: %s\n", line);
 
740
    }
 
741
  else
 
742
    {
 
743
      log_error ("unsupported inquiry `%s'\n", line);
 
744
      rc = ASSUAN_Inquire_Unknown;
 
745
    }
 
746
 
 
747
  return rc; 
 
748
}
 
749
 
 
750
static AssuanError
 
751
run_command_status_cb (void *opaque, const char *line)
 
752
{
 
753
  ctrl_t ctrl = opaque;
 
754
 
 
755
  if (opt.verbose)
 
756
    {
 
757
      log_info ("dirmngr status: %s\n", line);
 
758
    }
 
759
  if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
 
760
    {
 
761
      if (ctrl)
 
762
        {
 
763
          for (line += 8; *line == ' '; line++)
 
764
            ;
 
765
          if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
 
766
            return ASSUAN_Canceled;
 
767
        }
 
768
    }
 
769
  return 0;
 
770
}
 
771
 
 
772
 
 
773
 
 
774
/* Pass COMMAND to dirmngr and print all output generated by Dirmngr
 
775
   to stdout.  A couple of inquiries are defined (see above).  ARGC
 
776
   arguments in ARGV are given to the Dirmngr.  Spaces, plus and
 
777
   percent characters within the argument strings are percent escaped
 
778
   so that blanks can act as delimiters. */
 
779
int
 
780
gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
 
781
                           int argc, char **argv)
 
782
 
783
  int rc;
 
784
  int i;
 
785
  const char *s;
 
786
  char *line, *p;
 
787
  size_t len;
 
788
  struct run_command_parm_s parm;
 
789
 
 
790
  rc = start_dirmngr ();
 
791
  if (rc)
 
792
    return rc;
 
793
 
 
794
  parm.ctx = dirmngr_ctx;
 
795
 
 
796
  len = strlen (command) + 1;
 
797
  for (i=0; i < argc; i++)
 
798
    len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
 
799
  line = xtrymalloc (len);
 
800
  if (!line)
 
801
    return OUT_OF_CORE (errno);
 
802
 
 
803
  p = stpcpy (line, command);
 
804
  for (i=0; i < argc; i++)
 
805
    {
 
806
      *p++ = ' ';
 
807
      for (s=argv[i]; *s; s++)
 
808
        {
 
809
          if (!isascii (*s))
 
810
            *p++ = *s;
 
811
          else if (*s == ' ')
 
812
            *p++ = '+';
 
813
          else if (!isprint (*s) || *s == '+')
 
814
            {
 
815
              sprintf (p, "%%%02X", *s);
 
816
              p += 3;
 
817
            }
 
818
          else
 
819
            *p++ = *s;
 
820
        }
 
821
    }
 
822
  *p = 0;
 
823
 
 
824
  rc = assuan_transact (dirmngr_ctx, line,
 
825
                        run_command_cb, NULL,
 
826
                        run_command_inq_cb, &parm,
 
827
                        run_command_status_cb, ctrl);
 
828
  xfree (line);
 
829
  log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
 
830
  return map_assuan_err (rc);
 
831
}